I am running a SQL Query as follows:
SELECT a.id as id,a.name as name , a.price as price , a.saleprice as saleprice, a.images as images, a.slug as slug,a.hover_name as hover_name, MATCH (a.name) AGAINST ('+"blue cushion"') AS title_relevance FROM gc_products a WHERE ( ( ( MATCH (a.name) AGAINST ('+"blue cushion"') ) OR (a.sku like '%blue cushion%') ) and (a.enabled=1) ) ORDER BY title_relevance DESC
But It is giving me wrong results it is also showing me records where name is like "blue candle" , "red cushion"
I have also tried
MATCH (a.name) AGAINST ('blue cushion')
MATCH (a.name) AGAINST ('+blue cushion')
MATCH (a.name) AGAINST ('+blue +cushion')
It's not necessary that both the words be together.They can be any where in name but it is necessary that both the words must be there in name. '+' sign means 0 or more while I need at least one time.
But same result coming. I want if there are more than one words to match then it should match all the words in name.
MATCH (a.name) AGAINST ('blue +cushion')
You have to use the IN BOOLEAN MODE modifier, because by default MySQL performs a natural language search.
With this modifier, certain characters have special meaning at the
beginning or end of words in the search string.
Source: Boolean Full-Text Searches
Just rewrite your query like this:
SELECT a.id as id,a.name as name , a.price as price , a.saleprice as saleprice,
a.images as images, a.slug as slug,a.hover_name as hover_name,
MATCH (a.name) AGAINST ('+"blue cushion"' IN BOOLEAN MODE) AS title_relevance
FROM gc_products a
WHERE ( ( ( MATCH (a.name) AGAINST ('+"blue cushion"' IN BOOLEAN MODE) )
OR (a.sku like '%blue cushion%') )
AND (a.enabled=1) )
ORDER BY title_relevance DESC
Related
lets say I have table posts with this columns:
top_totle,title,sub_title,text
I need to have full text search on all this column and order by relevance where top_title need to be more important then title etc.
so i have 2 question which are the same, what is the best way of making an index for this and how to format the query to best support this index?
index options:
I can create combined full text index on all of this column or create separate index for each of this column
which is the prefered way?
option 1:
SELECT
title,
MATCH (top_title) AGAINST ('text' IN BOOLEAN MODE) as toptitle_score,
MATCH (title) AGAINST ('text' IN BOOLEAN MODE) as title_score,
MATCH (sub_text) AGAINST ('text' IN BOOLEAN MODE) as sub_text_score,
FROM
`posts`
WHERE
MATCH (top_title,title , sub_text ) AGAINST ('text' IN BOOLEAN MODE)
and `posts`.`deleted_at` IS NULL
AND `published_at` IS NOT NULL
Order by toptitle_score desc,
Order by title_score desc ,
Order by subtext_score desc
option 2:
SELECT
title,
MATCH (top_title) AGAINST ('text' IN BOOLEAN MODE) as toptitle_score,
MATCH (title) AGAINST ('text' IN BOOLEAN MODE) as title_score,
MATCH (sub_text) AGAINST ('text' IN BOOLEAN MODE) as sub_text_score,
FROM
`posts`
WHERE
(MATCH (top_title) AGAINST ('text' IN BOOLEAN MODE)
or MATCH (title) AGAINST ('text' IN BOOLEAN MODE)
or MATCH (sub_text) AGAINST ('text' IN BOOLEAN MODE))
and `posts`.`deleted_at` IS NULL
AND `published_at` IS NOT NULL
Order by toptitle_score desc,
Order by title_score desc ,
Order by subtext_score desc
option 3:
is there some smarter way?
Option 1 is good. It needs 4 FT indexes (one per column, plus one with all 3 columns). Don't repeat ORDER BY:
ORDER BY toptitle_score DESC ,
title_score DESC ,
subtext_score DESC
Option 2 is not a viable contender. It needs only 3 indexes (not much savings) but is a lot slower due to OR.
Option 3... (Option 1, as fixed, plus...)
The ORDER BY you are using is probably "wrong" for what you want. For example, it will shove to the end of the list any rows without text in toptitle. Perhaps you want some "weighted" version:
ORDER BY
9 * top_title_score +
3 * title_score +
1 * sub_text_score DESC
(The 9,3,1 are rather arbitrary. It says that if 'text' shows up more than 3 times in title, that is more important than showing up once in top_title -- or something like that.)
I am trying to enhance a third part (awesome) django framework named django-watson and I currently need to make my way through a so far unknown mysql option, the MATCH (...) AGAINST (...).
So, I already know how to retrieve an exact phrase, which is doing:
SELECT *
FROM patient_db
WHERE MATCH ( Name, id_number )
AGAINST ('"exact phrase"' IN BOOLEAN MODE);
An I also know how to retrieve results that contain words from a list:
SELECT *
FROM patient_db
WHERE MATCH ( Name, id_number )
AGAINST ('+keyword1 +keyword2' IN BOOLEAN MODE);
But I need a third option, which is mixing the two above quoted. I'd like to do something like the google search: "exact phrase" +keyword1 +keyword2.
_PS: when I search for "exact phrase" -keyword1 it works exactly as desired _
Any Ideas?
Try this.
SELECT *
FROM patient_db
WHERE MATCH ( Name, id_number )
AGAINST ('+keyword1 +keyword2' IN BOOLEAN MODE)
OR MATCH ( Name, id_number )
AGAINST ('"exact phrase"' IN BOOLEAN MODE)
This is my SQL Query:
SELECT filename
FROM video
WHERE MATCH (title, description) AGAINST
('sports' IN BOOLEAN MODE);
I'm searching the title and description fields for the word sports (case insensitive)
Now I want to count the number of times that the word score appeared on those fields, but independently... So I want to get something like this: n_title=2, n_description=1.
I already have tried this query, and it works...
SELECT filename,
ROUND ((LENGTH(description) - LENGTH( REPLACE ( description, "sports", ""))) / LENGTH("sports")) AS count
FROM video
but it's not case insensitive, and when I type sports it doesn't came up with any results, because on the database it's "saved" as "Sports" (with the uppercase "S").
Now my problem is how can I "concatenate" this 2 queries, and use them as one. So I can search for any word case insensitive, and also count the number of occurrences from each field.
This is what you are looking for (fiddle):
SELECT
filename,
(
CHAR_LENGTH(title)
- CHAR_LENGTH( REPLACE(LOWER(title), "sports", "") )
) / CHAR_LENGTH("sports") AS cnt_title,
(
CHAR_LENGTH(description)
- CHAR_LENGTH( REPLACE(LOWER(description), "sports", ""))
) / CHAR_LENGTH("sports") AS cnt_desc
FROM video
WHERE MATCH (title, description) AGAINST ('sports' IN BOOLEAN MODE);
REPLACE is case-sensitive by definition. The trick is to handle a lowercased version of the string. Also, your should use CHAR_LENGTHinstead of LENGTH. The former counts characters whereas the latter counts bytes (and you are using UTF8).
I've heared alot of similar discussion but I havent seen a direct solution.
SELECT * FROM patient_db WHERE
MATCH ( Name, id_number ) AGAINST ('%$term%' IN BOOLEAN MODE);
Isn't there something simple around my '%$term%' I need to do to enable multiple-word searching?
Unfortunately, there is no way to directly say, "I want one of these n words" in a MySQL fulltext query. Your only real option is
SELECT * FROM patient_db WHERE
MATCH ( Name, id_number ) AGAINST ('%$term%' IN BOOLEAN MODE)
OR MATCH ( Name, id_number ) AGAINST ('%$term2%' IN BOOLEAN MODE)
OR MATCH ( Name, id_number ) AGAINST ('%$term3%' IN BOOLEAN MODE)
;
Just curious, but why are you searching a column named id_number for text?
SELECT *
FROM `thread`
WHERE forumid NOT IN (1,2,3) AND IF( LEFT( title, 1) = '#', 1, 0)
ORDER BY title ASC
I have this query which will select something if it starts with a #. What I want to do is if # is given as a value it will look for numbers and special characters. Or anything that is not a normal letter.
How would I do this?
If you want to select all the rows whose "title" does not begin with a letter, use REGEXP:
SELECT *
FROM thread
WHERE forumid NOT IN (1,2,3)
AND title NOT REGEXP '^[[:alpha:]]'
ORDER BY title ASC
NOT means "not" (obviously ;))
^ means "starts with"
[[:alpha:]] means "alphabetic characters only"
Find more about REGEXP in MySQL's manual.
it's POSSIBLE you can try to cast it as a char:
CAST('#' AS CHAR)
but i don't know if this will work for the octothorpe (aka pound symbol :) ) because that's the symbol for starting a comment in MySQL
SELECT t.*
FROM `thread` t
WHERE t.forumid NOT IN (1,2,3)
AND INSTR(t.title, '#') = 0
ORDER BY t.title
Use the INSTR to get the position of a given string - if you want when a string starts, check for 0 (possibly 1 - the documentation doesn't state if it's zero or one based).