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.
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.
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.)
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 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`