Mysql

為什麼全文搜尋返回的行數少於 LIKE

  • September 11, 2017

我沒有讓全文搜尋按我的意願工作,而且我不理解結果列表中的差異。

範例語句:

SELECT `meldungstext`
FROM `artikel`
WHERE `meldungstext` LIKE '%punkt%'

返回 92 行。我收到了匹配的行,例如,meldungstext 列中的“Punkten”、“Zwei-Punkte-Vorsprung”和“Treffpunkt”。

我在“meldungstext”列上設置了全文索引並嘗試了這個:

SELECT `meldungstext`
FROM `artikel`
WHERE MATCH (`meldungstext`)
AGAINST ('*punkt*')

這僅返回 8 行。我只收到與“Punkt”本身匹配的行或我認為在“i-Punkt”中被視為“Punkt”的單詞。

然後我嘗試了布爾模式:

SELECT `meldungstext`
FROM `artikel`
WHERE MATCH (`meldungstext`)
AGAINST ('*punkt*' IN BOOLEAN MODE)

返回 44 行。我收到的行在meldungstext 列中有“Zwei-Punkte-Vorsprung”或“Treffpunkt”,但沒有“Punkten”。

為什麼會發生這種情況,如何設置“完全”工作的全文搜尋以防止在 where 子句中使用 LIKE ‘%%’?

我把你問題中的三個字元串添加到一個表格中,再加上三個字元串,pankt而不是punkt.

以下是使用 MySQL 5.5.12 for Windows 執行的

mysql> CREATE TABLE artikel
   -> (
   ->     id INT NOT NULL AUTO_INCREMENT,
   ->     meldungstext MEDIUMTEXT,
   ->     PRIMARY KEY (id),
   ->     FULLTEXT (meldungstext)
   -> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO artikel (meldungstext) VALUES
   -> ('Punkten'),('Zwei-Punkte-Vorsprung'),('Treffpunkt'),
   -> ('Pankten'),('Zwei-Pankte-Vorsprung'),('Treffpankt');
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql>

我使用 3 種不同的方法對錶執行這些查詢

  • MATCH ... AGAINST
  • LOCATE如在LOCATE函式中
  • LIKE

請注意差異

mysql> SELECT id,meldungstext,
   -> COUNT(IF(MATCH (`meldungstext`) AGAINST ('*punkt*' IN BOOLEAN MODE),1,0)) PunktMatch,
   -> IF(LOCATE('punkt',meldungstext)>0,1,0) PunktLocate,
   -> meldungstext  LIKE '%punkt%' PunktLike
   -> FROM `artikel` GROUP BY id,meldungstext;
+----+-----------------------+------------+-------------+-----------+
| id | meldungstext          | PunktMatch | PunktLocate | PunktLike |
+----+-----------------------+------------+-------------+-----------+
|  1 | Punkten               |          1 |           1 |         1 |
|  2 | Zwei-Punkte-Vorsprung |          1 |           1 |         1 |
|  3 | Treffpunkt            |          1 |           1 |         1 |
|  4 | Pankten               |          1 |           0 |         0 |
|  5 | Zwei-Pankte-Vorsprung |          1 |           0 |         0 |
|  6 | Treffpankt            |          1 |           0 |         0 |
+----+-----------------------+------------+-------------+-----------+
6 rows in set (0.01 sec)

mysql>

所有的 PunktMatch 值都應該是 3 個 1 和 3 個 0。

現在看我正常查詢它們

mysql> SELECT `meldungstext` FROM `artikel`
   -> WHERE MATCH (`meldungstext`) AGAINST ('*punkt*' IN BOOLEAN MODE);
+-----------------------+
| meldungstext          |
+-----------------------+
| Zwei-Punkte-Vorsprung |
| Punkten               |
+-----------------------+
2 rows in set (0.01 sec)

mysql> SELECT `meldungstext` FROM `artikel`
   -> WHERE LOCATE('punkt',meldungstext)>0;
+-----------------------+
| meldungstext          |
+-----------------------+
| Punkten               |
| Zwei-Punkte-Vorsprung |
| Treffpunkt            |
+-----------------------+
3 rows in set (0.00 sec)

mysql> SELECT `meldungstext` FROM `artikel`
   -> WHERE `meldungstext` LIKE '%punk%';
+-----------------------+
| meldungstext          |
+-----------------------+
| Punkten               |
| Zwei-Punkte-Vorsprung |
| Treffpunkt            |
+-----------------------+
3 rows in set (0.00 sec)

mysql>

OK 使用 MATCH .. AGAINST 與 punkt 不起作用。潘克特呢???

mysql> SELECT `meldungstext` FROM `artikel` WHERE `meldungstext` LIKE '%pankt%';
+-----------------------+
| meldungstext          |
+-----------------------+
| Pankten               |
| Zwei-Pankte-Vorsprung |
| Treffpankt            |
+-----------------------+
3 rows in set (0.00 sec)

mysql>

GROUP BY讓我們對 pankt執行我的大查詢

mysql> SELECT id,meldungstext,
   -> COUNT(IF(MATCH (`meldungstext`) AGAINST ('*pankt*' IN BOOLEAN MODE),1,0)) PanktMatch,
   -> IF(LOCATE('pankt',meldungstext)>0,1,0) PanktLocate,
   -> meldungstext  LIKE '%pankt%' PanktLike
   -> FROM `artikel` GROUP BY id,meldungstext;
+----+-----------------------+------------+-------------+-----------+
| id | meldungstext          | PanktMatch | PanktLocate | PanktLike |
+----+-----------------------+------------+-------------+-----------+
|  1 | Punkten               |          1 |           0 |         0 |
|  2 | Zwei-Punkte-Vorsprung |          1 |           0 |         0 |
|  3 | Treffpunkt            |          1 |           0 |         0 |
|  4 | Pankten               |          1 |           1 |         1 |
|  5 | Zwei-Pankte-Vorsprung |          1 |           1 |         1 |
|  6 | Treffpankt            |          1 |           1 |         1 |
+----+-----------------------+------------+-------------+-----------+
6 rows in set (0.01 sec)

mysql>

這也是錯誤的,因為我應該看到 PanktMatch 的 3 個 0 和 3 個 1。

我嘗試了別的東西

mysql> SELECT id,meldungstext, MATCH (`meldungstext`) AGAINST ('+*pankt*' IN BOOLEAN MODE) PanktMatch, IF(LOCATE('pankt',meldungstext)>0,1,0) PanktLocate, meldungstext  LIKE '%pankt%' PanktLike FROM `artikel` GROUP BY id,meldungstext;
+----+-----------------------+------------+-------------+-----------+
| id | meldungstext          | PanktMatch | PanktLocate | PanktLike |
+----+-----------------------+------------+-------------+-----------+
|  1 | Punkten               |          0 |           0 |         0 |
|  2 | Zwei-Punkte-Vorsprung |          0 |           0 |         0 |
|  3 | Treffpunkt            |          0 |           0 |         0 |
|  4 | Pankten               |          1 |           1 |         1 |
|  5 | Zwei-Pankte-Vorsprung |          1 |           1 |         1 |
|  6 | Treffpankt            |          0 |           1 |         1 |
+----+-----------------------+------------+-------------+-----------+
6 rows in set (0.00 sec)

mysql>

我在 pankt 上加了一個加號,得到了不同的結果。什麼 2 而不是 3 ???

根據MySQL 文件,請注意它對萬用字元的說明:

星號用作截斷(或萬用字元)運算符。與其他運算符不同,它應該附加到要受影響的單詞上。如果單詞以 * 運算符之前的單詞開頭,則單詞匹配。

如果使用截斷運算符指定單詞,則不會從布爾查詢中刪除它,即使它太短(由 ft_min_word_len 設置確定)或停用詞。出現這種情況是因為單詞不是太短或停用詞,而是作為前綴,必須以以前綴開頭的單詞的形式出現在文件中。假設 ft_min_word_len=4。然後搜尋 ‘+word +the*’ 可能會返回比搜尋 ‘+word +the’ 更少的行數:

前一個查詢保持原樣,並且要求文件中同時出現單詞和 the*(以 the 開頭的單詞)。

後一個查詢被轉換為 +word(只需要 word 存在)。the 太短又是一個停用詞,任何一個條件都足以導致它被忽略。

基於此,萬用字元適用於令牌的背面,而不適用於正面。鑑於此,輸出必須是正確的,因為 3 個 punkt 的起始標記中有 2 個。與 pankt 相同的故事。這至少解釋了為什麼 3 行中有 2 行以及為什麼行數更少。

引用自:https://dba.stackexchange.com/questions/21118