32b*_*oat 12 mysql myisam full-text-search
我没有按照我的意愿进行全文搜索,而且我不明白结果列表中的差异。
示例语句:
SELECT `meldungstext`
FROM `artikel`
WHERE `meldungstext` LIKE '%punkt%'
Run Code Online (Sandbox Code Playgroud)
返回 92 行。我在meldungstext 列中收到具有匹配项的行,例如“Punkten”、“Zwei-Punkte-Vorsprung”和“Treffpunkt”。
我在“meldungstext”列上设置了全文索引并尝试了这个:
SELECT `meldungstext`
FROM `artikel`
WHERE MATCH (`meldungstext`)
AGAINST ('*punkt*')
Run Code Online (Sandbox Code Playgroud)
这仅返回 8 行。我只收到与“Punkt”本身或我认为在“i-Punkt”中被视为“Punkt”的单词匹配的行。
然后我尝试了布尔模式:
SELECT `meldungstext`
FROM `artikel`
WHERE MATCH (`meldungstext`)
AGAINST ('*punkt*' IN BOOLEAN MODE)
Run Code Online (Sandbox Code Playgroud)
返回 44 行。我收到的行在列 meldungstext 中包含“Zwei-Punkte-Vorsprung”或“Treffpunkt”,但没有包含“Punkten”的行。
为什么会发生这种情况,如何设置“完全”工作的全文搜索以防止在 where 子句中使用 LIKE '%%'?
Rol*_*DBA 14
我把你问题中的三个字符串添加到一个表中,再加上三个字符串,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>
Run Code Online (Sandbox Code Playgroud)
我使用 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>
Run Code Online (Sandbox Code Playgroud)
所有 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>
Run Code Online (Sandbox Code Playgroud)
OK 使用 MATCH .. AGAINST 与 punkt 不起作用。pankt 呢???
mysql> SELECT `meldungstext` FROM `artikel` WHERE `meldungstext` LIKE '%pankt%';
+-----------------------+
| meldungstext |
+-----------------------+
| Pankten |
| Zwei-Pankte-Vorsprung |
| Treffpankt |
+-----------------------+
3 rows in set (0.00 sec)
mysql>
Run Code Online (Sandbox Code Playgroud)
让我们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>
Run Code Online (Sandbox Code Playgroud)
这也是错误的,因为我应该看到 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>
Run Code Online (Sandbox Code Playgroud)
我在 pankt 中添加了一个加号,但得到了不同的结果。什么2而不是3???
根据MySQL 文档,请注意它对通配符的说明:
*
星号用作截断(或通配符)运算符。与其他运算符不同,它应该附加到要影响的词之后。如果单词以 * 运算符之前的单词开头,则匹配。
如果用截断运算符指定了一个单词,则它不会从布尔查询中删除,即使它太短(由 ft_min_word_len 设置确定)或停用词也是如此。发生这种情况是因为该词不被视为太短或停用词,而是被视为必须以前缀开头的词的形式出现在文档中的前缀。假设 ft_min_word_len=4。然后搜索 '+word +the*' 返回的行可能比搜索 '+word +the' 返回的行数少:
前一个查询保持原样,要求文档中同时出现 word 和 the*(以 the 开头的单词)。
后一个查询被转换为 +word(只需要出现 word)。the 既太短又是一个停用词,任何一个条件都足以导致它被忽略。
基于此,通配符适用于令牌的背面,而不适用于正面。鉴于此,输出必须正确,因为 3 个 punkt 的起始标记中有 2 个。与 pankt 相同的故事。这至少解释了为什么 3 个中有 2 个以及为什么行数更少。
归档时间: |
|
查看次数: |
13910 次 |
最近记录: |