match against doesn't work with the word "when" - mysql

When desc contains the string: zoom when wifi dies for 1 second
Query 1:
SELECT * FROM `pics` WHERE MATCH(title, desc, owntags, usertags) AGAINST('+zoom* +wifi*' IN BOOLEAN MODE)
No problem, I get the row!
Query 2:
SELECT * FROM `pics` WHERE MATCH(title, desc, owntags, usertags) AGAINST('+zoom* +when*' IN BOOLEAN MODE)
No results! So when belongs to sql commands.
So how to solve this?

You need to learn some basics about full text search. One very important concept are stop words. These are words that are not included in the full-text index, because they are so common or add little meaning (at least from the perspective of the person who created the stop word list . . . a famous problem involves the band The Who).
The word 'when' is a common stop word and a default stop word in MySQL (see here and here). So, it is not being indexed.
You will need to recreate your full text indexes, either removing all stop words or using your own custom list.

Related

MySQL full text search by relevancy with wildcard

I need to search products and sort them by relevancy , for that I tried this MySQL query
SELECT *, MATCH(`SubProductName`) AGAINST ('+app*' IN BOOLEAN MODE) AS
relevance FROM `tblsubproducts1` WHERE MATCH(SubProductName) AGAINST
('+app*' IN BOOLEAN MODE) ORDER BY relevance DESC
That query for example returns : Apple Thunderbolt, Apple TV ... as results. which is right.
But when I try with '+usb*' it doesn't return any rows, while the database contains a row with SubProductName USB-C Charge Cable that I can find by matching against '+cable*'
To clarify,I want the search to work with partial words like 'app' for apple which is why I added *, but why it doesn't always seem to work is what's confusing me here. Is it the - in USB-C or ... ?
If you are using MyISAM, then the minimum word length for full text indexing is 4. (This is documented here.)
In other words, "usb" is not even in the index. You need to change this parameter and re-build the index.

match against not making sense

This is my filter text:
Oliver used book
If I search for 'Oliver' it works, if I search for 'book' it works but if I search for 'used' it does not work.
Heater white fan HEOP1322
Heater -> works : white -> works : fan -> does not work : HEOP -> does not work : HEOP1322 -> works.
My query is like this:
SELECT * FROM table WHERE MATCH(filter) AGAINST ('fan' IN BOOLEAN MODE)
SELECT * FROM table WHERE MATCH(filter) AGAINST ('HEOP' IN BOOLEAN MODE)
SELECT * FROM table WHERE MATCH(filter) AGAINST ('used' IN BOOLEAN MODE)
Why d'hell does the word used not work and the word book works? They have the same length.
I also tried this suggestions Mysql search for string and number using MATCH() AGAINST() without success.
Edit: Solved, follow this instructions.
XAMPP MySQL - Setting ft_min_word_len
"used" is one of the default MySQL full text stopwords: https://dev.mysql.com/doc/refman/5.1/en/fulltext-stopwords.html. Stopwords are words which are ignored because they are too frequent in the (English) language and would not positively contribute to the result of a full text search. If you're only querying for single words, a LIKE %..% query may be more suited than a full-blown full text search.

mysql fulltext boolean search with asterix

I have a query like below:
SELECT prd_id FROM products WHERE MATCH (prd_search_field)
AGAINST ('+gul* +yetistiren* +adam*' in boolean mode);
This doesn't return the rows including 'gul'.
http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html
The document says this.
Then a search for '+word +the*' will likely return fewer rows than a
search for '+word +the':
The former query remains as is and requires both word and the* (a word starting with the) to be present in the document.
The latter query is transformed to +word (requiring only word to be present). the is both too short and a stopword, and either condition is enough to cause it to be ignored.
So as I understood the too short word condition must not be applied in my situation since I use * after each word. What's wrong with this?
As a solution I use the below query but since it's slow, I need to find another solution. Any idea would be appreciated? Thanks in advance..
SELECT prd_id FROM products WHERE 1 AND MATCH (prd_search_field)
AGAINST ('+yetistiren* +adam*' in boolean mode) AND prd_search_field
LIKE '%gul%';
As a note ft_min_word_length=4 as default in all shared hosting environments, and I cannot change it.

mysql boolean mode fulltext search with wildcards and literals

I'm pretty new to MySQL full-text searches and I ran into this problem today:
My company table has a record with "e-magazine AG" in the name column. I have a full-text index on the name column.
When I execute this query the record is not found:
SELECT id, name FROM company WHERE MATCH(name) AGAINST('+"e-magazi"*' IN BOOLEAN MODE);
I need to work with quotes because of the dash and to use the wildcard because I implement a "search as you type" functionality.
When I search for the whole term "e-magazine AG", the record is found.
Any ideas what I'm doing wrong here? I read about adding the dash to the list of word characters (config update needed) but I'm searching for a way to do this programmatically.
This clause
MATCH(name) AGAINST('+"e-magazi"*' IN BOOLEAN MODE);
Will search for a AND "e" AND NOT "magazi"; i.e. the - inside "e-magazi" will be interpreted as a not even though it is inside quotation marks.
For this reason it will not work as expected.
A solution is to apply an extra having clause with a LIKE.
I know this having is slow, but it will only be applied to the results of the match, so not too many rows should be involved.
I suggest something like:
SELECT id, name
FROM company
WHERE MATCH(name) AGAINST('magazine' IN BOOLEAN MODE)
HAVING name LIKE '%e-magazi%';
MySQL fulltext treats the word e-magazine in a text as a phrase and not as a word. Because of that it results the two words e and magazine. And while it builds the search index it does not add the e to the index because of the ft_min_word_len (default is 4 chars).
The same length limitation is used for the search query. That is the reason why a search for e-magazine returns exactly the same results as a-magazine because a and - is fully ignored.
But now you want to find the exact phrase e-magazine. By that you use the quotes and that is the complete correct way to find phrases, but MySQL does not support operators for phrases, only for words:
https://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html
With this modifier, certain characters have special meaning at the beginning or end of words in the search string
Some people would suggest to use the following query:
SELECT id, name
FROM company
WHERE MATCH(name) AGAINST('e-magazi*' IN BOOLEAN MODE)
HAVING name LIKE 'e-magazi%';
As I said MySQL ignores the e- and searches for the wildcard word magazi*. After those results are optained it uses HAVING to aditionally filter the results for e-magazi* including the e-. By that you will find the phrase e-magazine AG. Of course HAVING is only needed if the search phrase contains the wildcard operator and you should never use quotes. This operator is used by your user and not you!
Note: As long you do not surround the search phrase with % it will find only fields that start with that word. And you do not want to surround it, because it would find bee-magazine as well. So maybe you need an additional OR HAVING name LIKE ' %e-magazi%' OR HAVING NAME LIKE '\\n%e-magazi%' to make it usable inside of texts.
Trick
But finally I prefer a trick so HAVING isn't needed at all:
If you add texts to your database table, add them additionally to a separate fulltext indexed column and replace words like up-to-date with up-to-date uptodate.
If a user searches for up-to-date replace it in the query with uptodate.
By that you can still find specific in user-specific but up-to-date as well (and not only date).
Bonus
If a user searches for -well-known huge ports MySQL treats that as not include *well*, could include *known* and *huge*. Of course you could solve that with an other extra query variant as well, but with the trick above you remove the hyphen so the search query looks simply like that:
SELECT id
FROM texts
WHERE MATCH(text) AGAINST('-wellknown huge ports' IN BOOLEAN MODE)

Against not returning score

There is something wrong with this query? This one works sometimes and sometimes not. For example with the word 'seven' it doesn't return any score, but i know that it appears on 29 rows at least in the body however it return as score 0.
With other words it work ok but not with this one. Anyone know why or have a different solution to sort it by relevance?
SELECT *,
( (MATCH(articles.name) AGAINST('seven'))*5 +
(MATCH(articles.subtitle) AGAINST('seven'))*3 +
(MATCH(articles.body) AGAINST('seven'))) AS search_score
FROM articles
LEFT JOIN matches ON articles.match=matches.id
ORDER BY search_score DESC
EDIT: I noticed that 'seven' is a stop word. There is other way to do this? stopwords
Add COALESCE(value,0) around each score.
Problem
If the word is too common, i.e. occurs in 50%+ of the rows, MySQL considers it a STOP-word and will not match against it.
Then there's the stop-word list (which you've already noticed)
See: http://dev.mysql.com/doc/refman/5.5/en/fulltext-stopwords.html
Solution
This answer: where to edit mysql fulltext stopword lists?
Tells you how to override/replace the default stop word list.
Here's the link to the MySQL docs page: http://dev.mysql.com/doc/refman/5.5/en/fulltext-fine-tuning.html