$qstring = "SELECT titulo as value, id FROM blogs WHERE titulo LIKE '%".$term."%' LIMIT 5";
$qstring = "SELECT titulo as value, id FROM blogs WHERE MATCH(titulo) AGAINST ('.$term.') LIMIT 5";
The first one will return results but not really related to the query
the second will return:
Can't find FULLTEXT index matching the column list
why?
check value in $term that should be greater then 3 in case of FULLTEXT index search otherwise it will return null
The minimum and maximum lengths of words to be indexed are defined by the ft_min_word_len and ft_max_word_len system variables. The default minimum value is four characters. If you change either value, you must rebuild your FULLTEXT indexes. For example, if you want three-character words to be searchable, you can set the ft_min_word_len variable by putting the following lines in an option file:
match() only works on field which have a FULLTEXT on them, exactly as the error message says. You'd have to do:
ALTER TABLE blogs ADD FULLTEXT INDEX tituolo_ft (titulo);
before you can use fulltext operations on the field.
As the error message implies, you can't use MATCH ... AGAINST unless there is a FULLTEXT index on the field you are comparing.
The LIKE statement should work though. I think the problem may be the double quotes in your pattern which are superfluous and will require corresponding quotes in the database value. Please show what database data you are trying to match.
In addition to the FULLTEXT index mentioned by others it looks like you are not properly quoting your text in the AGAINST clause. I think it should be:
AGAINST ('".$term."')
Or else, since you already have double quotes around your query just embed the variable:
AGAINST ('$term')
Related
I would like to use the replace function inside a match function, to remove \n characters before it searches matching rows. Otherwise, for example, if the text is FULLTEXT\nsearch, and the search is search, it will not match.
Here is my query (simplified) :
SELECT * FROM messages WHERE MATCH(REPLACE(body,'\\n',' ')) AGAINST ('mysearch' IN BOOLEAN MODE)
But it throws an error...
[EDIT]
After #Shadow 's answer, I tried this :
SELECT * FROM (SELECT REPLACE(body,'\\n',' ') AS rb FROM messages) AS rbody WHERE MATCH(rb) AGAINST ('mysearch');
I think the idea is correct, but I get an error ERROR 1210 (HY000): Incorrect arguments to MATCH. I think this is because I didn't index the column rb (FULLTEXT INDEX (rb)), so the MATCH () AGAINST () operation won't work.
So I update my question : How can one index a column of a subquery
The answer is that you cannot dynamically remove \n character sequence within a match() call. As MySQL manual on match() says:
MATCH() takes a comma-separated list that names the columns to be searched.
You either have to store \n differently, not as a character sequence or you need to have a separate field in which these characters are already filtered out and this additional field is used for fulltext searches.
Actually, waiting for a better solution, I will just add a column raw_body to my table, where I will store the exact body (I won't escape it with real_sacpe_string, I will just manually replace " and ' by \" and \'), and I will prepare the query and bind the params. However, I don't know if it is secure enough against sqlinjection.
[UPDATE]
Actually I found out that I didn't even needed to manually escape quotes, since the prepared statement is enough to prevent sqli. So I think I will just keep this solution for the moment
So I'm having some difficulty creating exact searches in MySQL fulltext.
In my database, I'm trying to find jobs with a specific keyword in its title.
So I might try
WHERE MATCH(jobTitle) AGAINST ('"fs sales"' IN BOOLEAN MODE)
However, this finds matches on "sales", not "fs sales"
How can I ensure that "fs sales" matches EXACTLY on "fs sales" and not "sales"?
Table is InnoDB for reference.
"fs" is probably excluded from the search as too short.
Check the value of innodb_ft_min_token_size and manual: https://dev.mysql.com/doc/refman/5.6/en/fulltext-fine-tuning.html
You have to rebuild the index after changing that variable.
Your query should work. My guess, though is that you did not change the minimum word length, so "fs" was never indexed. See here for information on this.
Other possibilities are that there are other characters in the text, perhaps characters you do not see.
You might try this
select t.*
from (select . . .
WHERE MATCH(jobTitle) AGAINST ('+fs +sales' IN BOOLEAN MODE)
) t
where jobTitle like '%fs sales%';
This only does the like on the returned set from the match.
However, my best guess is that innodb_ft_min_token_size is set to its default value of 3, so "fs" is not being indexed.
you can do it like
select col1, col2 from table_name where text_column like '%fs sales%'
this will return all the records having fs sales in them..
My MySQL table is not returning results with a MATCH (col) AGAINST ('') query.
The table is simple:
id | url | fullTextIndex
And my query is
SELECT *, Match(fullTextIndex) AGAINST ("7f7f7f807f8080807f8080807f7f7f807c828888808a86967e8b858d7f89838a76829e958f7badb68084a3a38384899077848b877f799f9c85799fa2827d8c8a ") FROM Pictures;
The last column, the match, is always 0. Except, I know for a fact that the string above is contained, verbatim, in one of the values.
Things to note:
The string is only in that row (so it is not in more than 50% of rows, so it shouldn't be ignored).
This is not the Full value
The column is a bigText column
When I use INSTR, I get the value 1 (which is correct)
Any ideas why this query might not be working?
There seems to be a (configurable) upper limitation on the length of the words considered for indexation:
http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_ft_max_word_len
You can check the current value with SHOW VARIABLES LIKE "ft_max_word_len";
It returns 84 on my server, and your string is 128 chars long.
Suggested fix:
Add this line to your my.cnf file: ft_max_word_len=128 (or whatever max length you need)
Rebuild your indexes as advised on the MySQL website: REPAIR TABLE tbl_name QUICK;
I have keywords like "some-or-other" where the hyphens matter in the search through my mysql database. I'm currently using the fulltext function.
Is there a way to escape the hyphen character?
I know that one option is to comment out #define HYPHEN_IS_DELIM in the myisam/ftdefs.h file, but unfortunately my host does not allow this. Is there another option out there?
Here's the code I have right now:
$search_input = $_GET['search_input'];
$keyword_safe = mysql_real_escape_string($search_input);
$keyword_safe_fix = "*'\"" . $keyword_safe . "\"'*";
$sql = "
SELECT *,
MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix') AS score
FROM table_name
WHERE MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix')
ORDER BY score DESC
";
From here http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
One solution to find a word with a dashes or hyphens in is to use FULL TEXT SEARCH IN BOOLEAN MODE, and to enclose the word with the hyphen / dash in double quotes.
Or from here http://bugs.mysql.com/bug.php?id=2095
There is another workaround. It was recently added to the manual:
"
Modify a character set file: This requires no recompilation. The true_word_char() macro
uses a “character type” table to distinguish letters and numbers from other
characters. . You can edit the contents in one of the character set XML
files to specify that '-' is a “letter.” Then use the given character set for your
FULLTEXT indexes.
"
Have not tried it on my own.
Edit: Here is some more additional info from here http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html
A phrase that is enclosed within double quote (“"”) characters matches only rows that contain the phrase literally, as it was typed. The full-text engine splits the phrase into words and performs a search in the FULLTEXT index for the words. Prior to MySQL 5.0.3, the engine then performed a substring search for the phrase in the records that were found, so the match must include nonword characters in the phrase. As of MySQL 5.0.3, nonword characters need not be matched exactly: Phrase searching requires only that matches contain exactly the same words as the phrase and in the same order. For example, "test phrase" matches "test, phrase" in MySQL 5.0.3, but not before.
If the phrase contains no words that are in the index, the result is empty. For example, if all words are either stopwords or shorter than the minimum length of indexed words, the result is empty.
Some people would suggest to use the following query:
SELECT id
FROM texts
WHERE MATCH(text) AGAINST('well-known' IN BOOLEAN MODE)
HAVING text LIKE '%well-known%';
But by that you need many variants depending on the used fulltext operators. Task: Realize a query like +well-known +(>35-hour <39-hour) working week*. Too complex!
And do not forget the default len of ft_min_word_len so a search for up-to-date returns only date in your results.
Trick
Because of that I prefer a trick so constructions with HAVING etc aren't needed at all:
Instead of adding the following text to your database table: "The Up-to-Date Sorcerer" is a well-known science fiction short story. copy the hyphen words without hypens to the end of the text inside a comment: "The Up-to-Date Sorcerer" is a well-known science fiction short story.<!-- UptoDate wellknown -->
If the users searches for up-to-date remove the hyphen in the sql query:
MATCH(text) AGAINST('uptodate ' IN BOOLEAN MODE)
By that you're user can find up-to-date as one word instead of getting all results that contain only date (because ft_min_word_len kills up and to).
Of course before you echo the texts you should remove the <!-- ... --> comments.
Advantages
the query is simpler
the user is able to use all fulltext operators as usual
the query is faster.
If a user searches for -well-known +science MySQL treats that as not include *well*, could include *known* and must include *science*. This isn't what the user expected. The trick solves that, too (as the sql query searches for -wellknown +science)
Maybe simpler to use the Binary operator.
SELECT *
FROM your_table_name
WHERE BINARY your_column = BINARY "Foo-Bar%AFK+LOL"
http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html#operator_binary
The BINARY operator casts the string following it to a binary string. This is an easy way to force a column comparison to be done byte by byte rather than character by character. This causes the comparison to be case sensitive even if the column is not defined as BINARY or BLOB. BINARY also causes trailing spaces to be significant.
My preferred solution to this is to remove the hyphen from the search term and from the data being searched. I keep two columns in my full-text table - search and return. search contains sanitised data with various characters removed, and is what the users' search terms are compared to, after my code has sanitised those as well.
Then I display the return column.
It does mean I have two copies of the data in my database, but for me that trade-off is well worth it. My FT table is only ~500k rows, so it's not a big deal in my use case.
I am trying to follow: http://dev.mysql.com/doc/refman/4.1/en/fulltext-natural-language.html
in an attempt to improve search queries, both in speed and the ability to order by score.
However when using this SQL ("skitt" is used as a search term just so I can try match Skittles).
SELECT
id,name,description,price,image,
MATCH (name,description)
AGAINST ('skitt')
AS score
FROM
products
WHERE
MATCH (name,description)
AGAINST ('skitt')
it returns 0 results. I am trying to find out why, I think I might have set my index's up wrong I'm not sure, this is the first time I've strayed away from LIKE!
Here is my table structure and data:
Thank you!
By default certain words are excluded from the search. These are called stopwords. "a" is an example of a stopword. You could test your query by using a word that is not a stopword, or you can disable stopwords:
How can I write full search index query which will not consider any stopwords?
If you want to also match prefixes use the truncation operator in boolean mode:
*
The asterisk serves as the truncation (or wildcard) operator. Unlike the other operators, it should be appended to the word to be affected. Words match if they begin with the word preceding the * operator.