MySQL MATCH () AGAINST () FULLTEXT Index - достижение частичного совпадения строки в сочетании с фразовым соответствием - PullRequest
4 голосов
/ 11 июля 2020

У меня есть таблица со столбцом содержимое с индексом FULLTEXT .

Я хочу воспользоваться скоростью MATCH () на большом тексте.

Я хочу, чтобы поиск был максимально точным.

Когда я ищу строку фразы « большой грузовик » следующим образом:

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"' IN BOOLEAN MODE);

Некоторые экземпляры пропущены.

MyTable:

|   content    |
----------------
|Large \n truck| FOUND ✓
----------------
|large truck   | FOUND ✓
----------------
|large trucks  | *PLURAL MISSED!
----------------
|large truckl  | *TYPE-O MISSED!

Если я использую стандартный LIKE / подстановочный знак метод:

SELECT * FROM  `MyTable` WHERE  `content` LIKE  '%large truck%'

MyTable:

|   content    |
----------------
|Large \n truck| *MISSED!
----------------
|large truck   | FOUND ✓
----------------
|large trucks  | FOUND ✓
----------------
|large truckl  | FOUND ✓

Кажется, я не могу использовать поиск PHRASE с подстановочными знаками вместе:

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck*"' IN BOOLEAN MODE); **DOES NOT WORK**

ИЛИ

SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"*' IN BOOLEAN MODE); **DOES NOT WORK**

Итак ...

Как мне успешно использовать MATCH () AGAINST () для поиска фразы и вернуть все экземпляры - даже совпадения частичных строк без учета регистра?

Ответы [ 2 ]

4 голосов
/ 17 июля 2020

Уловка, которую я часто использую с FT, состоит в том, чтобы сделать это в два этапа:

  1. Сделайте MATCH, надеясь получить весь желаемый текст, но, возможно, некоторые дополнительные результаты.
  2. AND с другим условием - LIKE (быстрее) или REGEXP (более мощным).

MATCH будет быстрым из-за FT; другая часть будет выполнена второй, так что это будет быстро, потому что не так много строк для проверки.

Это соответствует вашим критериям:

SELECT * FROM MyTable
    WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE)
      AND content REGEXP "large[[:space:]]+truck";

Другими словами, запрос будет выполнен примерно так:

  1. Допустим, в таблице 10K строк.
  2. Будет вычислено выражение FT. MATCH будет очень быстрым (из-за того, как он разработан). Он найдет все строки с "большим" и "грузовиком *" в любом месте content. Теперь, скажем, есть 30 строк, которые этому удовлетворяют.
  3. Остальная часть WHERE вычисляется. Но это делается только против этих 30 рядов. Таким образом, даже несмотря на то, что REGEXP является дорогостоящим, это делается нечасто.
  4. Тогда, возможно, возвращается 14 строк.

Эффект net заключается в том, что весь запрос работает "быстро", что было одним из ваших требований.

Примечание: мне нужна была вторая часть, чтобы предотвратить эти

large green truck
the truck is large

В зависимости от версии вам может потребоваться этот REGEXP вместо: "large\\s+truck".

2 голосов
/ 11 июля 2020

Вот быстрый взлом с REGEXP, но он не решает проблему, поскольку он не использует полнотекстовый индекс:

SELECT * 
FROM MyTable 
WHERE content REGEXP("large[[:space:]]+truck*");

Конечно, вы также можете использовать индекс FT, выполняя поиск без точной фразы:

SELECT * 
FROM MyTable 
WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE);

Но в конечном итоге это будет включать записи, которые вам не нужны, так как это не то же самое, что поиск точной фразы.

К сожалению, поиск фразы (двойные кавычки - "") и оператор усечения (подстановочный знак - *) не будет работать независимо от того, используете ли вы InnoDB или MyISAM. Он не работает с оператором расстояния и с InnoDB (который, вероятно, исходит из того же источника). Я думаю, это связано с тем, как хранятся данные полнотекстового индекса.

...