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.)
Related
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.
I want relevancy for exact "production house in goa". it also results anything that contain Goa.
SELECT * FROM `app_search` WHERE MATCH (`keywords`) AGAINST
("production house in goa" in boolean mode)
order by MATCH (`keywords`) AGAINST ("production house in goa" in boolean mode)
desc, rank desc;
Thanks
Deleting old table and recreating with fulltext index on keywords and below query solve the problem.
SELECT *, MATCH (`keywords`) AGAINST
('software development in florida'
IN BOOLEAN MODE) AS score
FROM `ftextsearch` WHERE MATCH (keywords) AGAINST
('software development in florid'
IN BOOLEAN MODE) order by score desc,rank desc
Query also return relevancy of search in score.
We use fulltext search on a french CMS ( SPIP ). The resultat of a search with a minus word doesn't seems correct. We tried the sql request generated by the CMS in phpMyAdmin :
SELECT t.id_zotspip, t.titre, t.resume,
MATCH(t.`titre`) AGAINST ('+corrosion -bacteria' IN BOOLEAN MODE) * 10
+ MATCH(t.`titre`,t.`resume`) AGAINST ('+corrosion -bacteria' IN BOOLEAN MODE) * 2.2 AS score
FROM `spip_zotero311`.spip_zitems AS t
WHERE ((MATCH(t.`titre`) AGAINST ('+corrosion -bacteria' IN BOOLEAN MODE))
OR (MATCH(t.`titre`,t.`resume`) AGAINST ('+corrosion -bacteria' IN BOOLEAN MODE)))
GROUP BY t.id_zotspip ORDER BY score DESC LIMIT 0,500
We get results with bacteria in the resume...
The type of the table is MyISAM but the type of the base is InnoDB.
Any suggestions ?
Thank you.
The problem is in OR clause inside where. You should replace OR inside WHERE clause with AND.
This example shows that only one fulltext index is needed. http://www.vionblog.com/mysql-full-text-search-with-multiple-words/
Here's the example:
ALTER TABLE products ADD FULLTEXT(title, sdescription, ldescription)
SELECT *,
MATCH(`title`) AGAINST ('+iphone +case +4s' IN BOOLEAN MODE) * 10 as rel1,
MATCH(`sdescription`) AGAINST ('+iphone +case +4s' IN BOOLEAN MODE) * 3 as rel2,
MATCH(`ldescription`) AGAINST ('+iphone +case +4s' IN BOOLEAN MODE) as rel3,
FROM products
WHERE MATCH (title, sdescription, ldescription)
AGAINST ('+iphone +case +4s' IN BOOLEAN MODE)
ORDER BY (rel1)+(rel2)+(rel3) DESC;
And this answer suggests that three fulltext indexes are needed to do the same. How can I manipulate MySQL fulltext search relevance to make one field more 'valuable' than another?
I want to make one column more valuable than others like it's been done in the above query. I'm confused how many indexes are needed for that, one or three?
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