Mysql fulltext search didn't find exact phrase - mysql

I have a table with column name with fulltext index -
In this table there is many rows but some of them contain the phrase "aberlour 18" exactly at start like here -
But when I search using the fulltext search with exact name from the table -
SELECT * FROM `whiskybase_bottles` WHERE MATCH(`name`) AGAINST('Aberlour 18 year old')
It finds it only on 6th place -
How can I improve it to find it first?
I don't want to use "LIKE" search because fulltext works better for my needs on other cases.
I already decreased the "innodb ft min token size" param to be 2 instead of 3 to include the age statement and recreated the index after it -

If you are trying to find rows that have "Aberlour 18 year old" included in the name but not necessarily the entire name, you can use the + operator that is used for boolean full text searches. Without the + operator, your query is searching for phrases that match the search exactly and does not select phrases that have other words and characters like you want.
Your code would look something like this:
SELECT *
FROM `whiskybase_bottles`
WHERE MATCH(`name`) AGAINST('+"Aberlour 18 year old"' IN BOOLEAN MODE)
You can learn more about BOOLEAN MODE and the related operators here:
https://www.w3resource.com/mysql/mysql-full-text-search-functions.php
For a general search with a variable you can do something like this:
SELECT *
FROM `whiskybase_bottles`
WHERE MATCH(`name`) AGAINST(concat('+\"', search_phrase, '\"') IN BOOLEAN MODE)

If you want to rank the exact phrase on the top.
Use this code instead:
SELECT *,MATCH (name) AGAINST( 'Aberlour 18 year old' IN BOOLEAN MODE) as score
FROM `whiskybase_bottles`
WHERE MATCH(`name`) AGAINST('Aberlour 18 year old')
ORDER BY name = 'Aberlour 18 year old' DESC, score DESC

Related

query that returns rows that do not contain a word in MySql

I am trying to make a query where I select all the rows that do not contain a specific word, for this I have a fulltext type index in this column, try the following bolt works:
SELECT *
FROM products
WHERE MATCH(title) AGAINST(' -Dolo' IN BOOLEAN MODE)
So how can I perform this search?
If I have understood you correctly you want to find all the rows from the table that do not contain a word'Dolo'.
Well you can use NOT operator for that.
SELECT *
FROM products
WHERE NOT MATCH(title) AGAINST('Dolo');
Here is a DEMO.
Also, you can use it like this(because as the OP has asked: "if the whole word is "dolorem", would this query work?"):
SELECT title as Title
, MATCH(title) AGAINST('Dolo*' IN BOOLEAN MODE) as Score
FROM products
WHERE MATCH(title) AGAINST('Dolo*' IN BOOLEAN MODE) = 0;
* is a wildcard.
Other signs are described here: https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html
Here is the DEMO for the second example.

having with match and group_concat in mysql

I' trying to write a MYSQL query which looks for a string in an aggregation of fields.
The following query finds all the concatenations where "io sono" is present:
SELECT chapter, GROUP_CONCAT(text_search) AS aggregated_chapters
FROM bible_it_cei_2008
GROUP BY chapter
HAVING aggregated_chapters LIKE '%io sono%';
However, trying to use MATCH... AGAINST instead of LIKE:
SELECT chapter, GROUP_CONCAT(text_search) AS aggregated_chapters
FROM bible_it_cei_2008
GROUP BY chapter
HAVING MATCH ( aggregated_chapters ) AGAINST ( '+"io sono"' IN BOOLEAN MODE);
returns the error:
#1210 - Incorrect arguments to MATCH
Isn't there any way to use MATCH AGAINST with GROUP_CONCAT?
Isn't there any way to use MATCH AGAINST with GROUP_CONCAT?
No. That's not the way FULLTEXT search works in MySQL.
If your table contains the columns chapter and text_search, and you hope to find the values of chapter matching text search, you want something like this.
SELECT chapter,
MATCH(text_search) AGAINST ('+"io sono"' IN NATURAL LANGUAGE MODE) AS score
FROM bible_it_cei_2008
To get this to work you'll need to create an appropriate FULLTEXT index.

How to search text using MATCH...AGAINST query?

Table
id name
--- ------
1 chinu
2 sanjib
3 chinmay
My MYSQL Query
SELECT * FROM users WHERE MATCH (name) AGAINST ('chi' IN BOOLEAN MODE)
In above query i am getting 0 record.
My output will be coming
1 chinu
3 chinmay
How to get my actual record using MATCH...AGAINST query?
EDIT - If i am searching chinu instead of chi i am getting 1 record.
You need to add an asterisk to the 'chi' to indicate that the query should match against all that contain the string and not just the string itself. Just using the string 'chi' will only match exactly 'chi' for example.
change your query to read
SELECT * FROM users WHERE MATCH (name) AGAINST ('chi*' IN BOOLEAN MODE)
and you should get the results you expect.
I think you forgot the + sign:
SELECT * FROM users WHERE MATCH (name) AGAINST ('+chi' IN BOOLEAN MODE)
Or if it is an exact phrase, use double quotes to surround the string:
SELECT * FROM users WHERE MATCH (name) AGAINST ('"chi"' IN BOOLEAN MODE)
I am the first to admit that this is not easy to find. MySQL full text search uses a system variable called ft_min_word_length. The default value is 4, as shown here.
Because you are searching for a 3-character word, it is not being indexed. Hence it is not found.
More information is available in the documentation on fine tuning the search. But the basic idea is that you need to change the value of the parameter and rebuild the index.
For your particular query, though, you just need to include wildcards, as explained in other answers.

ORDER BY in MySql based on LIKE condition

I am facing difficulty in sorting the result based on field in mysql. Say for example I am searching the word "Terms" then I should get the results which starts with 'Terms' first and then 'Terms and' as next and then 'Terms and conditions' and so on.
Any one please help out who to fetch the search result based on my requirements in efficient manner using mysql query.
SELECT * FROM your_table WHERE your_column LIKE "Terms%" ORDER BY your_column;
Based on the storage engine and mysql version you probably can use the full text search capabilities of MySQL. For example:
SELECT *, MATCH (your_column) AGAINST ('Terms' IN BOOLEAN MODE) AS relevance
FROM your_table
WHERE MATCH (your_column) AGAINST ('Terms' IN BOOLEAN MODE)
ORDER BY relevance
You can find more info here: http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html
Or if you don't want FTS another possible solution where ordering is strictly based on the length (difference) of the strings.
SELECT * FROM your_table WHERE your_column LIKE "Terms%" ORDER BY ABS(LENGTH(your_column) - LENGTH('Terms'));
You are looking for fulltext search. Below a very simple example
SELECT id,name MATCH (name) AGAINST ('string' > 'string*' IN BOOLEAN MODE) AS score
FROM tablename WHERE MATCH (name) AGAINST ('string' > 'string*' IN BOOLEAN MODE)
ORDER BY score DESC
The advantage of this is that you can control the value of words. This is very basic, you can 'up' some matches or words (or 'down' them)
In my example an exact match ('string') would get a higher score than the string with something attached ('string*'). The following line is even one step broader:
'string' > 'string*' > '*string*'
This documentation about fulltextsearch explains allot. It's a long read, but worth it and complete.
Don't use fulltext index if you search for prefix string!
Using LIKE "Term%" the optimizer will be able to use a potential index on your_column:
SELECT * FROM your_table
WHERE your_column LIKE "Terms%"
ORDER BY CHAR_LENGTH(your_column),your_column
Note the ORDER BY clause: it first sorts by string length, and only use alphabetcal order to sort strings of equal length.
And please, use CHAR_LENGTH and not LENGTH as the first count the number of characters, whereas the later count number of bytes. Using a variable length encoding such as utf8, this would made a difference.

Unexpected behaviour in MySQL with Boolean-Mode-Query with quoted hyphenated string

I have a problem or rather an understanding problem with a hyphenated searchstring which is quoted.
In my Table there is a table with a column 'company'.
One of the entries in that column is: A-Z Electro
The following examples are simplified a lot (though the real query is much more complex) - but the effect is still the same.
When I do the following search, I don't get the row with the above mentioned company:
SELECT i.*
FROM my_table i
WHERE MATCH (i.company) AGAINST ('+\"A-Z\" +Electro*' IN BOOLEAN MODE)
GROUP BY i.uid ORDER BY i.company ASC LIMIT 0, 40;
If I do the following search, get the row with the above mentioned company (notice only changed the - to a + before "A-Z":
SELECT i.*
FROM my_table i
WHERE MATCH (i.company) AGAINST ('-\"A-Z\" +Electro*' IN BOOLEAN MODE)
GROUP BY i.uid ORDER BY i.company ASC LIMIT 0, 40;
I also get the row, if I remove the operator completely:
SELECT i.*
FROM my_table i
WHERE MATCH (i.company) AGAINST ('\"A-Z\" +Electro*' IN BOOLEAN MODE)
GROUP BY i.uid ORDER BY i.company ASC LIMIT 0, 40;
Can anyone explain to me this behaviour? Because I would expect, when searching with a +, I should get the result too...
I just checked the table index with myisam_ftdump.
Two-Character-Words are indexed properly as there are entries like
14f2e8 0.7908264 ab
3a164 0.8613265 dv
There is also an entry:
de340 0.6801047 az
I suppose this should be the entry for A-Z - so the search should find this entry, shouldn't it?
The default value of ft_min_word_len is 4. See this link for information on that. In short, your system isn't indexing words of less than 4 characters.
Why is this important? Well:
A-Z is less than 4 characters long
...therefore it's not in the index
...but your first query +"A-Z" states it must be in the index in order for the match to succeed
The other two (match if it's not in the index, match if either this or that is in the index) work because it's not in the index.
The hyphen is a red herring - the reason is because "A-Z" is three characters long and your FT index ignores it.