MySql Full Index search not working - mysql

I set the example code here
http://sqlfiddle.com/#!2/6aa9ec/1
Below mentioned DB query used for searching the word Samsung but its not working
SELECT `idREQUEST`, `USER_NAME`, `idCATEGORY`, `TITLE`, `DESCRIPTION`, `IMAGE_URL1`, `IMAGE_URL2`, `IMAGE_URL3`, `POST_DATE`
FROM `requests`
WHERE MATCH (`TITLE`,`DESCRIPTION`) AGAINST('Samsung')

You can use Boolean Full-Text Searches
SELECT `idREQUEST`,
`USER_NAME`,
`idCATEGORY`,
`TITLE`,
`DESCRIPTION`,
`IMAGE_URL1`,
`IMAGE_URL2`,
`IMAGE_URL3`,
`POST_DATE`
FROM `requests`
WHERE MATCH (`TITLE`,`DESCRIPTION`) AGAINST('+Samsung' IN BOOLEAN MODE)
According to docs
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 + operator indicate that a
word is required to be present, respectively, for a match to
occur.
DEMO

This query looks for tiles and descriptions which the value is merely 'Samsung' But there are no entries in your table which are only 'Samsung'. Hence I'd suggest you to use %
SELECT `idREQUEST`, `USER_NAME`, `idCATEGORY`, `TITLE`, `DESCRIPTION`,
`IMAGE_URL1`, `IMAGE_URL2`, `IMAGE_URL3`, `POST_DATE`
FROM `requests`
where `TITLE` like '%Samsung%' or `DESCRIPTION` like '%Samsung%'
This is the link

Related

MySQL full text search - no partial recognition

I'm trying to build a keyword search tool based on mysql and I can only get results for full words while I would like to get results for partial matches too.
My db structure looks like this:
My db content looks like this:
This query works:
select * from chromext_keyword where matches (keyword) against ('Redmi')
But this one doesn't work (no result):
select * from chromext_keyword where matches (keyword) against ('red')
I tried with % but it did not solve the problem. I tried the natural language option as well as boolean but it didn't help.
Update with create table query:
CREATE TABLE chromext_keywords (
id int(10) NOT NULL,
keyword text NOT NULL,
blacklist text NOT NULL,
category text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
and insert:
INSERT INTO chromext_keywords (id, keyword, blacklist, category) VALUES
(1, 'Redmi Note 10', '9,8,pro', '2'),
(2, 'Realme GT', '6,7,8,narzo', '2');
and I added full text:
ALTER TABLE chromext_keywords
ADD UNIQUE KEY id (id);
ALTER TABLE chromext_keywords ADD FULLTEXT KEY keyword (keyword);
I have also tried innoDb and Myisam
Am I missing something?
Thanks
You should check for Minimum word lenght setting ..
in mysql the minimum length for full text search in limited by the param
ft_min_word_len
and the defualt value is for words > 3
take a look at the related docs
https://dev.mysql.com/doc/refman/8.0/en/fulltext-fine-tuning.html
I have finally found the answer.
The following query works:
SELECT * FROM chromext_keywords WHERE match(keyword) against('(re*)') IN BOOLEAN MODE)
With multiple keywords:
SELECT * FROM chromext_keywords WHERE match (keyword) against ('(+red*+not*)') IN BOOLEAN MODE)
I still need to figure out how to cover spelling mistakes. If anyone has an idea, let me know.

Mysql full text returnig NULL

My mysql code.
CREATE TABLE `videos` (
`id` int(50) NOT NULL,
`user_id` int(250) NOT NULL,
`title` varchar(250) NOT NULL,
`discription` text NOT NULL,
`video_path` varchar(250) NOT NULL,
`tumbnail_path` varchar(250) NOT NULL,
`paid` int(250) NOT NULL,
`date` date NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `videos` (`id`, `user_id`, `title`, `discription`, `video_path`, `tumbnail_path`, `paid`, `date`) VALUES
(1, 4, 'This is a new video', '<p>This is a new video from eduladder in at this video we are discribing how stuffs works</p>\r\n', 'uploadvid/xIdivzexFZXzr6bng2E9mU3PNvMVq0Iz.mp4', 'uploadthump/1AT1EsgJ--6iVLxEwEFRkWa9ADqqD1BG.jpg', 0, '2018-12-10'),
(2, 4, 'New Video for testig', '<p>This is a new video for testing purpose only</p>\r\n', 'uploadvid/_rsIHMc2giVoWV6aRixCoEUk0gKcDhDI.mp4', 'uploadthump/zA_t-2DMusUDvg9xVPwmRAn5-59He76-.jpg', 0, '2018-12-12'),
(3, 4, 'Some New Videos', '<p>This is a record of some new videos</p>\r\n', 'uploadvid/jPzlU3xSJaZVm7EzZu_JfaXq8kAK_1Vc.mp4', 'uploadthump/M_SZodSk20ba2FsXw3X1WVq7a48S_cj3.jpg', 0, '2018-12-13'),
(4, 4, 'Old video', '<p>This is an old video</p>\r\n', 'uploadvid/yaYiDBru2c7fCcosPmrj94JhZ5waxbu8.mp4', 'uploadthump/FhRXXen99DEa0d-8w5m2FDcvFyxlZgx4.png', 0, '2018-12-13'),
(5, 4, 'Almost new video and edited', '<p>This is about almost new video and editted version</p>\r\n', 'uploadvid/YOVPqiFO5xUnCtFAdYzgiY2wzsCnSQ11.mp4', 'uploadthump/MO1faxOKDNESee0gG5SQZYeantzlrPYM.png', 0, '2018-12-13');
ALTER TABLE `videos` ADD FULLTEXT(`title`,`discription`);
And the query which I am excecuting is here.
SELECT * ,
MATCH (title, discription) AGAINST ('New') AS score
FROM videos
WHERE MATCH (title, discription) AGAINST ('New')
ORDER BY score
DESC LIMIT 20
Here's a mysql fiddle https://www.db-fiddle.com/f/jUs9EABZjuBL956WtnTbqx/3
But it is giving me nothing where am I going wrong how can I fix this issue?
Since you asked for it to work with MySql 5.5 in your comment:
Plz see the udated code db-fiddle.com/f/jUs9EABZjuBL956WtnTbqx/3
innodb wont work it is myql version <5.6
Then it's 2 different case. For MySql 5.7, Stopword list applies only.
But for MySql 5.5 from your latest fiddle here are the 2 reasons :
The 1st reason this is not working is because the word you are searching for is present in 50% or more of the total rows, so it is considered as Common Word and won't match as a result. See the Mysql 5.5 FullText Search Docs :
There are three types of full-text searches:
A natural language search interprets the search string as a phrase in
natural human language (a phrase in free text). There are no special
operators, with the exception of double quote (") characters. The
stopword list applies. In addition, words that are present in 50% or
more of the rows are considered common and do not match.
And the 2nd one is because by default the FullText Search Length is set to 4. So you need to change it in my.cnf and add value :
[mysqld]
ft_min_word_len = 3
to be able to search 3 characters words.
But since in db-fiddle I cannot modified the length, here is a modified working fiddle where the word Older is used. Older is not present on 50% of rows and its length is >= 4.
Seems to be an issue with Full text Stop-words on the myisam engine, I changed the engine to InnoDB and I can get results.
See this link. Full-Text Stopwords
To fully disable stopwords, add this ft_stopword_file = '', to your database configuration file, the repair the table to rebuild indexes,
REPAIR TABLE tbl_name QUICK. and restart the server

MySQL Fulltext MATCH/AGAINST showing not always results

I have the following table setup:
CREATE TABLE IF NOT EXISTS `search_table` (
`fulltext_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Entity ID',
`data_index` longtext COMMENT 'Data index',
PRIMARY KEY (`fulltext_id`),
FULLTEXT KEY `FTI_CATALOGSEARCH_FULLTEXT_DATA_INDEX` (`data_index`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Search table'
AUTO_INCREMENT=1;
INSERT INTO `search_table` (`fulltext_id`, `data_index`)
VALUES (1, 'Test Hello abc');
Then I try a full text search on it with 3 different query texts:
SELECT `s`.`fulltext_id`, MATCH (s.data_index) AGAINST ('Test' IN BOOLEAN MODE) AS `relevance` FROM `search_table` AS `s`
WHERE (MATCH (s.data_index) AGAINST ('Test' IN BOOLEAN MODE));
SELECT `s`.`fulltext_id`, MATCH (s.data_index) AGAINST ('Hello' IN BOOLEAN MODE) AS `relevance` FROM `search_table` AS `s`
WHERE (MATCH (s.data_index) AGAINST ('Hello' IN BOOLEAN MODE));
SELECT `s`.`fulltext_id`, MATCH (s.data_index) AGAINST ('abc' IN BOOLEAN MODE) AS `relevance` FROM `search_table` AS `s`
WHERE (MATCH (s.data_index) AGAINST ('abc' IN BOOLEAN MODE));
Only the first query (the search for Test) gives a result back, the other two not. I don't understand why?
You should check the list of currently defined stopwords. You can do this like this:
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
More information about MySQL stopwords can be found here: https://dev.mysql.com/doc/refman/5.7/en/fulltext-stopwords.html
Hello for example is a known stopword therefore it is being ignored during FTS matching. If you check comments on the linked MySQL doc page you will find links from user to English language stopwords lists, like https://www.ranks.nl/stopwords/.
Note, MySQL as well as other DB engines allows you to specify your own custom list of stop words. So you should check both pre-defined system stopwords list and any existing custom stopwords lists.

INSTR(str,substr) does not work when str contains 'é' or 'ë' and substr only 'e'

In another post on stackoverflow, I read that INSTR could be used to order results by relevance.
My understanding of col LIKE '%str%' andINSTR(col, 'str')` is that they both behave the same. There seems to be a difference in how collations are handled.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO users (name)
VALUES ('Joël'), ('René');
SELECT * FROM users WHERE name LIKE '%joel%'; -- 1 record returned
SELECT * FROM users WHERE name LIKE '%rene%'; -- 1 record returned
SELECT * FROM users WHERE INSTR(name, 'joel') > 0; -- 0 records returned
SELECT * FROM users WHERE INSTR(name, 'rene') > 0; -- 0 records returned
SELECT * FROM users WHERE INSTR(name, 'joël') > 0; -- 1 record returned
SELECT * FROM users WHERE INSTR(name, 'rené') > 0; -- 1 record returned
Although INSTR does some conversion, it finds ë in é.
SELECT INSTR('é', 'ë'), INSTR('é', 'e'), INSTR('e', 'ë');
-- returns 1, 0, 0
Am I missing something?
http://sqlfiddle.com/#!2/9bf21/6 (using mysql-version: 5.5.22)
This is due to bug 70767 on LOCATE() and INSTR(), which has been verified.
Though the INSTR() documentation states that it can be used for multi-byte strings, it doesn't seem to work, as you note, with collations like utf8_general_ci, which should be case and accent insensitive
This function is multi-byte safe, and is case sensitive only if at least one argument is a binary string.
The bug report states that although MySQL does this correctly it only does so when the number of bytes is also identical:
However, you can easily observe that they do not (completely) respect collations when looking for one string inside another one. It seems that what's happening is that MySQL looks for a substring which is collation-equal to the target which has exactly the same length in bytes as the target. This is only rarely true.
To pervert the reports example, if you create the following table:
create table t ( needle varchar(10), haystack varchar(10)
) COLLATE=utf8_general_ci;
insert into t values ("A", "a"), ("A", "XaX");
insert into t values ("A", "á"), ("A", "XáX");
insert into t values ("Á", "a"), ("Á", "XaX");
insert into t values ("Å", "á"), ("Å", "XáX");
then run this query, you can see the same behaviour demonstrated:
select needle
, haystack
, needle=haystack as `=`
, haystack LIKE CONCAT('%',needle,'%') as `like`
, instr(needle, haystack) as `instr`
from t;
SQL Fiddle

Increment Column on Select

Evening,
I'm currently running this query:
SELECT `id`, `type`, `controller` FROM `urls` WHERE `url` = :url;
UPDATE `urls` SET `views` = `views` + 1 WHERE `url` = :url;
I run this when a page is loaded and it increments the views column by 1. However, I'm interested to know if there is a way (maybe using something like a trigger) that the view column could be incremented automatically.
I can't find an exact duplicate but Syntax for "RETURNING" clause in Mysql PDO and Mysql returning clause equivalent give you the answer you need.
MySQL does not have an equivalent of Oracle and PostgreSQLs returning into clause. You'll have to use two separate statements.
If you're expecting to do a lot of updates it might (conditional, it might not) be better to keep the number of views in a separate table, especially as you're not returning the view count in your query. Something like the following:
insert into url_views values(url);
select `id`, `type`, `controller` from `urls` where `url` = :url;
and then if you need the number of views:
select count(*)
from url_views
where url = :url
or use MySQLs insert ... select syntax.