I'm trying to create a fulltext query that matches ANY of multiple exact phrases and excluding others. In my test query. I want to select any record that has EITHER (or both) the exact phrase 'brown cow' OR 'green cat' AND NOT 'silver rhino'. I have set up test records with combinations of these three phrases and should return 3 records if I can get my query right.
Query 1
SELECT * FROM jos_sea_messages
WHERE ((Match(body,subject) Against('"+green cat"' IN BOOLEAN MODE) OR Match(body,subject) Against('"+brown cow"' IN BOOLEAN MODE))
AND ( Match(body,subject) Against('"-silver rhino"' IN BOOLEAN MODE)))
Returns 2 records- one of them with 'silver rhino', so not what I want
Query 2
SELECT * FROM jos_sea_messages
WHERE ((Match(body,subject) Against('"+green cat" "-silver rhino"' IN BOOLEAN MODE) OR Match(body,subject) Against('"+brown cow" "-silver rhino"' IN BOOLEAN MODE)))
Returns all records with any of the phrases, including 'silver rhino', so still not right
Query 3
SELECT * FROM jos_sea_messages
WHERE (Match(body,subject) Against('"+green cat" "+brown cow" "-silver rhino"' IN BOOLEAN MODE))
Returns a whole lot of rows, some of which I don't think have any of the exact phrases?
What is the proper syntax for finding records that have either (or both) exact phrases 'brown cow' and 'green cat' but must not contain 'silver rhino'?
Thanks in advance.
I figured it out. Here is my query:
SELECT * FROM jos_sea_messages WHERE (Match(body,subject) Against('"green cat" "brown cow" -"silver rhino"' IN BOOLEAN MODE))
The + aren't required because that would mean that both phrases were needed, and the - goes outside the double quotes.
Hope it helps someone else. I'm sure this type of requirement isn't unique
Related
I know how to get all results which contain a few words:
SELECT * FROM `table` WHERE MATCH (`row`) AGAINST ('+word1 +word2' IN BOOLEAN MODE)
But how I can all results which not contain words: "word1", "word2" ?? I need operator, something like "NOT IN". So how I can get from database everything records which not contain specific words in query using full text search?
Thanks.
You can just use NOT to negate the condition:
SELECT * FROM `table` WHERE NOT MATCH (`row`) AGAINST ('+word1 +word2' IN BOOLEAN MODE)
The MATCH condition is true on rows where it finds the words, and false where it does not find the words. Use NOT reverses the true/false result on each row.
Just like:
SELECT * FROM `table` WHERE NOT row = 'abc123'
would be true on all rows that are not the specific value 'abc123'.
I've got a problem using Match Against in my MySQL database, and I'm hoping someone can help.
This is the examples of the data in my database:
id name
1 really bitter chocolate
2 soft cheese
When I run this query:
SELECT * FROM food WHERE (name) LIKE "%bitter%"
This bring back the first result:
1 really bitter chocolate
However its part of a much larger query, and when I run the Match Against code, I don't get anything returned from either of these queries:
SELECT * FROM food WHERE MATCH (name) AGAINST ("bitter")
SELECT * FROM food WHERE MATCH (name) AGAINST ("bitter", IN BOOLEAN MODE)
I have full text searches turned on, and it works when I search the start of the name:
SELECT * FROM food WHERE MATCH (name) AGAINST ("really")
SELECT * FROM food WHERE MATCH (name) AGAINST ("really", IN BOOLEAN MODE)
Both of which returns:
1 really bitter chocolate
I've read through this for solutions: http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html
And I've looked here: mysql WHERE MATCH AGAINST
Can someone please see where I am going wrong or point me in the right direction?
Thanks!
EDIT
Ok as per Woot4Moo great answer below I've changed my code to remove the comma which shouldn't have been there. I've also added in the + and putting it in single quotes but still no luck.
My current query now looks like this:
SELECT * FROM food WHERE MATCH (name) AGAINST ('+bitter' IN BOOLEAN MODE)
But it's returning no results in query browser, and not returning any errors or warnings.
If this are the only two rows in your table then you have in 50% of the records the searched string and it will be ignored.
SELECT * FROM food WHERE MATCH (name) AGAINST ("bitter", IN BOOLEAN MODE)
looks like it should be:
SELECT * FROM food WHERE MATCH (name) AGAINST ('+bitter' IN BOOLEAN MODE)
notice how mine has the plus sign + and NO comma ,
Basing it off of the example here
MySQL can perform boolean full-text searches using the IN BOOLEAN
MODE modifier. With this modifier, certain characters have special
meaning at the beginning or end of words in the search string. In the
following query, the + and - operators indicate that a word is
required to be present or absent, respectively, for a match to occur.
Thus, the query retrieves all the rows that contain the word “MySQL”
but that do not contain the word “YourSQL”:
mysql> SELECT * FROM articles WHERE MATCH (title,body)
-> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
In this situation, I want to find all records that contain the name steve in one column and email#email.com in another. I know Im missing an operator, but i dont know which
SELECT firstname,lastname,middlename,company_name,
primary_emailaddress,alternate_emailaddress,personal_address_line1,
personal_address_line2,personal_address_city,facebook_username,
twitter_username,googleplus_username,linkedin_username,
personal_website_url,birthday_month,notes,personal_address_zipcode,
company_address_zipcode,home_phonenumber,company_phonenumber,
cell_phonenumber,birthday_day,birthday_year,hash,image_file
FROM contacts
WHERE (
MATCH(
firstname,lastname,
primary_emailaddress,alternate_emailaddress,personal_address_line1,
personal_address_city,company_name,
company_address_line1,company_address_city,
facebook_username,twitter_username,googleplus_username,linkedin_username,
personal_website_url
)
AGAINST ('Steve email#email.com' IN BOOLEAN MODE))
Match is faster than a like comparison. I think you can do it twice in a where clause:
SELECT firstname,lastname,middlename,company_name,
primary_emailaddress,alternate_emailaddress,personal_address_line1,
personal_address_line2,personal_address_city,facebook_username,
twitter_username,googleplus_username,linkedin_username,
personal_website_url,birthday_month,notes,personal_address_zipcode,
company_address_zipcode,home_phonenumber,company_phonenumber,
cell_phonenumber,birthday_day,birthday_year,hash,image_file
FROM contacts
WHERE MATCH (firstname) AGAINST ('Steve' IN BOOLEAN MODE) > 0 and
MATCH (primary_emailaddress, alternate_emailaddress)
AGAINST ('email#email.com' IN BOOLEAN MODE) > 0;
Unless you are really looking through every field, (i.e. John Stevenson would be considered a match on 'Steve') you can do this much simpler...
select *
from contacts
where firstname like '%Steve%'
and (primary_emailaddress like '%email#email.com%' or alternate_emailaddress like '%email#email.com%')
I write script for full-text search by descriptions of some objects. But I did not satisfied with default full-text search algorithm in boolean mode, so I try to modify it some way. I want to combine 3 several searches into one. First query I search for "exact phrase", second - all words of phrase present, third - at least one of words is present. And then return it by priority. I must do something like this:
SELECT
description,
MATCH(description) AGAINST ('"my search"' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('"my search"' in boolean mode)
UNION DISTINCT
SELECT
description,
MATCH(description) AGAINST ('+my +search' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('+my +search' in boolean mode)
UNION
SELECT
description,
MATCH(description) AGAINST ('my* search*' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('my* search*' in boolean mode)
As you can see, first block of rows will contain the most relevant results - exact phrase. Second block will contain less relevant rows, and third will contain all the rest.
But this query returns duplicated rows, in other words, row that exists in first block, can repeat again in second block, or third, even if I use UNION DISTINCT. But I want get global distinct set of rows for all three sub-selects. If row appears in first block, then it must not exist in seconds and third. How can I do this? Or may be you can give me more elegant solution for such kind of search?
OK re-read problem. Union all will give you all resutls, union should give you distinct results
Or you could just use
`Select distinct * from
(SELECT
description,
MATCH(description) AGAINST ('"my search"' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('"my search"' in boolean mode)
UNION DISTINCT
SELECT
description,
MATCH(description) AGAINST ('+my +search' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('+my +search' in boolean mode)
UNION
SELECT
description,
MATCH(description) AGAINST ('my* search*' in boolean mode) FROM search
WHERE MATCH(description) AGAINST ('my* search*' in boolean mode)) B`
I have the following MySQL query:
SELECT title, description
FROM some_table
WHERE MATCH (title,description) AGAINST ('+denver (REGEXP "[[:<:]]colorado[s]*[[:>:]]")' IN BOOLEAN MODE);
the "regexp" here looks for a "complete word" colorado (with or without the ending "s").
I want to actually select only those rows that have ("denver") AND ("colorado" or "colorados"). But I cannot put a "+" for the REGEXP. I tried but got 0 results, although there are rows in the table that match the requirement.
Any ideas on how I can get the "+" to work within against using a REGEXP?
I am constructing this from within a PHP script where "denver" and "colorado" are values of variables I use to construct the select statement.
My PHP/MySQL script would look somewhat like this:
SELECT title, description
FROM some_table
WHERE MATCH (title,description) AGAINST ('+$var1 (REGEXP "[[:<:]]$var2[s]*[[:>:]]")' IN BOOLEAN MODE);
I don't think it's possible to combine regular expressions and MATCH ... IN BOOLEAN MODE. You need to use the syntax for writing boolean expressions.
Boolean Full-Text Searches
Try something like this:
SELECT title, description
FROM some_table
WHERE MATCH (title,description)
AGAINST ('+denver +(colorado colorados)' IN BOOLEAN MODE);