MySQL fulltext search results fine tune - mysql

I have an InnoDB table with 5000 rows. Here is an example of my table named 'insitutes'.
id| name
1 | University of London
2 | Department of Maths University of London
3 | Department of Biology University of London
4 | Department of Chemistry University of London
5 | Department of Physics University of London
...
This is what my query looks like
SELECT *,
MATCH (name) AGAINST ('London University' IN BOOLEAN MODE) AS score
FROM insitutes
WHERE MATCH (name) AGAINST ('London University' IN BOOLEAN MODE)
ORDER BY score DESC
This is what my result will look like
Department of Biology University of London
Department of Maths University of London
Department of Chemistry University of London
University of London
....
I want to get 'University of London' as the first result. Saying this I mean I want to get the closest match to the search query.
By playing with my data I found out that changing the table type to MyISAM and modifying the query to 'IN NATURAL LANGUAGE MODE' will give me expected results. But I cannot use the table type MyISAM as it does not indexes words less than 4 charaters.

First of all, you can indeed control the minimum word size in your MyISAM fulltext index, with ft_min_word_len.
SET ft_min_word_len= 3
or whatever you need, will do it. You probably want to make sure it's set in your MySQL my.cnf file too, so if your server restarts it's still set.
Second, the word of in your search term is in the FULLTEXT stoplist. You can't use it for matching unless you remove it from the stoplist.
And, if you have managed to include of in your index, notice that the department name strings contain it twice, which will boost their score.
If you change FULLTEXT's configuration be sure to rebuild your index.
Third, as you know the order of your resultset comes from the score assigned to each row by FULLTEXT. FULLTEXT is designed as an assistance to human perception. It presents choices for a human to choose among, rather than precisely correct choices. Expecting perfectly predictable results from FULLTEXT is probably a mistake.

What ever letter We Can Use As Text. If U Have Problem Say Me More Clearly. Ok ?
I Think You Can Use Mysql Query Like This:
select
*, count(name)
from
insitutes
where
name like "%London University%"
order by
name desc;
Once Check This If This Statement Works Say Me Else Define Your Problem More Clearly.

Related

Is there any way to get the matched string or word in mysql

I am using Match() Against() in mysql.
What I want to do is somehow get the keyword that is matched with the string.
lets say the keyword is 'rain water'
and I want to find it in the table. Since its match() Against() It will match both rain and water individually and thats find. But I want to get the word which is matched.
Like if rain is matched i need the word rain if water is matched i need the word water.
example table
--------------------------------------------------------
id| text1 | text2
--------------------------------------------------------
1 rain water harvesting I have a new car
2 summer season heat I want to make tea
3 I want to go to paris I love to water plants
4 Its raining in england rain drops are falling
5 do not waste water we eat bun
6 water is essential I love to dance in rain
7 fire burns my laptop is old
8 we breathe air We eat good food
---------------------------------------------------------
This is the query I have reached so far
SELECT *,
MATCH(text1,text2) AGAINST('rain water' IN NATURAL LANGUAGE MODE) AS Word
FROM EXAMPLE_TABLE
WHERE MATCH(text1,text2) AGAINST('rain water' IN NATURAL LANGUAGE MODE)
MySQL does not directly offer you feedback about why your search term hit, apart from the aggregated score.
You can however extract that information if you match your result to each term separately, and this way create your own post-evaluation:
SELECT *,
CONCAT_WS(', ',
IF(MATCH(text1,text2) AGAINST('rain'), 'rain', null),
IF(MATCH(text1,text2) AGAINST('water'), 'water', null) ) as words
FROM EXAMPLE_TABLE
WHERE MATCH(text1,text2) AGAINST('rain water')
This will check your found rows against each term separately, and if it was a hit, appends the word to your result string.
In general though, things you do just to format your output belong into your application, which also usually has more flexibility in processing strings. If you e.g. want to order your terms by position or occurance in your result ("water, rain" instead of "rain, water"), a query-only solution will quickly become a mess (and if you'd still need it in MySQL, you would do it in a stored function and do basically the same as you would in e.g. php).

Finding the fastest speeds by exchange

I have a requirement to remove "duplicate" entries from a dataset, which is being displayed on the front-end of our application.
A duplicate is defined by the client as a speed test result which is in the same exchange.
Here is my current query,
SELECT id, isp, exchange_name, exchange_postcode_area, download_kbps, upload_kbps
FROM speedtest_results
WHERE postcode IS NOT NULL
AND exchange_name IS NOT NULL
ORDER BY download_kbps DESC, upload_kbps ASC
This query would return some data like this,
12062 The University of Bristol Bristol North BS6 821235 212132
12982 HighSpeed Office Limited Totton SO40 672835 298702
18418 University of Birmingham Victoria B9 553187 336889
14050 Sohonet Limited Lee Green SE13 537686 104439
19981 The JNT Association Holborn WC1V 335833 74459
19983 The JNT Association Holborn WC1V 333661 84397
5652 University of Southampton Woolston SO19 330320 64200
As you can see, there are two tests in the WC1V postcode area, which I'd like to aggregate into a single result, ideally using max rather than avg.
How can I modify my query to ensure that I am selecting the fastest speed test result for the exchange whilst still being able to return a list of all the max speeds?
Seems that I was far too hasty to create a question! I have since solved my own issue.
SELECT id, isp, exchange_name, exchange_postcode_area, MAX(download_kbps) as download_kbps, upload_kbps
FROM speedtest_results
WHERE exchange_name IS NOT NULL
AND postcode IS NOT NULL
GROUP BY exchange_name
ORDER BY MAX(download_kbps) DESC
LIMIT 20

mysql combining records from one table

I have a single table that uses test# as the primary key. Here is what that table looks like:
Test# Name VerbalScore readingScore Notes
1 Bobby 92 Good job
2 Bobby 40 You Suck Bobby
The problem is I want to view and be able to see when there are multiple verbal scores for the same Name (so be able to see if the person took the same test more than once).
I want to have some kind of select statement to get this result from the above table:
1 Bobby 92 40 Good job, You Suck Bobby
Is that possible?
I am not totally sure I understand what you mean by "see when there are multiple verbal scores" but with mysql 5+, try
SELECT
Name,
GROUP_CONCAT(VerbalScore),
GROUP_CONCAT(readingScore),
GROUP_CONCAT(Notes)
FROM
myTable
GROUP BY
Name;
GROUP_CONCAT is a mysql specific grouping function.

Querying normalized database, 3 tables

I have three tables in a MySQL database:
stores (PK stores_id)
states (PK states_id)
join_stores_states (PK join_id, FK stores_id, FK states_id)
The "stores" table has a single row for every business. The join_stores_states table links an individual business to each state it's in. So, some businesses have stores in 3 states, so they 3 rows in join_stores_states, and others have stores in 1 state, so they have just 1 row in join_stores_states.
I'm trying to figure out how to write a query that will list each business in one row, but still show all the states it's in.
Here's what I have so far, which is obviously giving me every row out of join_stores_states:
SELECT states.*, stores.*, join_stores_states.*
FROM join_stores_states
JOIN stores
ON join_stores_states.stores_id=stores.stores_id
JOIN states
ON join_stores_states.states_id=states.states_id
Loosely, this is what it's giving me:
store 1 | alabama
store 1 | florida
store 1 | kansas
store 2 | montana
store 3 | georgia
store 3 | vermont
This is more of what I want to see:
store 1 | alabama, florida, kansas
store 2 | montana
store 3 | georgia, vermont
Suggestions as to which query methods to try would be just as appreciated as a working query.
If you need the list of states as a string, you can use MySQL's GROUP_CONCAT function (or equivalent, if you are using another SQL dialect), as in the example below. If you want to do any kind of further processing of the states separately, I would prefer you run the query as you did, and then collect the resultset into a more complex structure (hashtable of arrays, as a simplest measure, but more complex OO designs are certainly possible) in the client by iterating over the resulting rows.
SELECT stores.name,
GROUP_CONCAT(states.name ORDER BY states.name ASC SEPARATOR ', ') AS state_names
FROM join_stores_states
JOIN stores
ON join_stores_states.stores_id=stores.stores_id
JOIN states
ON join_stores_states.states_id=states.states_id
GROUP BY stores.name
Also, even if you only need the concatenated string and not a data structure, some databases might not have an aggregate concatenation function, in which case you will have to do the client processing anyway. In pseudocode, since you did not specify a language either:
perform query
stores = empty hash
for each row from query results:
get the store object from the hash by name
if the name isn't in the hash:
put an empty store object into the hash under the name
add the state name to the store object's stores array

How to prioritize a LIKE query select based on string position in field?

I am attempting to query a table for a limited resultset in order to populate an autocomplete field in javascript. I am, therefore, using a LIKE operator with the partial string entered.
If I have, for example, a table such as:
tblPlaces
id country
1 Balanca
2 Cameroon
3 Canada
4 Cape Verde
5 Denmark
For the sake of this example, let's say I want two rows returning - and yeah, for this example, I made up a country there ;) I want to prioritize any instance where a partial string is matched at the beginning of country. The query I began using, therefore is:
SELECT id, country FROM tblPlaces WHERE country LIKE 'ca%' LIMIT 2
This returned 'Cameroon' and 'Canada' as expected. However, in instances where there are no two names in which the string is matched at the beginning of a word (such as 'de'), I want it to look elsewhere in the word. So I revised the query to become
SELECT id, country FROM tblPlaces WHERE country LIKE '%ca%' LIMIT 2
This then returned 'Cape Verde' and 'Denmark', but in doing so broke my original search for 'ca', which now returns 'Balanca' and 'Cameroon'.
So, my question is, how to go about this using a single query that will prioritize a match at the start of a word (perhaps I need to use REGEXP?) I am assuming also that if the 'country' column is indexed, these matches will at least be returned with subsequent alphabetical priority (i.e. Cameroon before Canada etc).
If you mean to prioritize matches that are Exactly at the start...
SELECT id, country
FROM tblPlaces
WHERE country LIKE '%ca%'
ORDER BY CASE WHEN country LIKE 'ca%' THEN 0 ELSE 1 END, country
LIMIT 2
EDIT
More generic and possibly faster (Assuming "closer to the start the 'better' the match")...
SELECT id, country
FROM tblPlaces
WHERE country LIKE '%ca%'
ORDER BY INSTR(country, 'ca'), country
LIMIT 2