Tam metin araması neden LIKE'dan daha az satır döndürüyor


10

Tam metin aramasını istediğim gibi çalıştırmıyorum ve sonuç listelerindeki farklılıkları anlamıyorum.

Örnek ifadeler:

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

92 satır döndürür. Sütun meldungstext'te "Punkten", "Zwei-Punkte-Vorsprung" ve "Treffpunkt" gibi eşleşmeleri olan satırları alıyorum.

"Meldungstext" sütununda bir tam metin dizini ayarlayın ve bunu denedim:

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

bu yalnızca 8 satır döndürür. Yalnızca "Punkt" ile eşleşen satırlar veya "i-Punkt" gibi "Punkt" olarak alındığını düşündüğüm kelimeler alıyorum.

Sonra boolean modunu denedim:

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

44 satır döndürür. Sütun meldungstext'te "Zwei-Punkte-Vorsprung" veya "Treffpunkt" olan satırları alıyorum, ancak "Punkten" olan satırları almıyorum.

Bu neden oluyor ve nerede-cümlesinde '%%' LIKE kullanılmasını önlemek için "tam" çalışan bir tam metin araması nasıl ayarlayabilirim?


1
Bu, büyük bir +1 hak ediyor çünkü bu sorun gerçekten incelenmiyor ve FULLTEXT dizine ekleme genellikle kabul ediliyor.
RolandoMySQLDBA

Yanıtlar:


13

Sorunuzdaki üç dizeyi alıp bir tabloya ve panktbunun yerine üç dizeye ekledim punkt.

Aşağıdakiler Windows için MySQL 5.5.12 kullanılarak yürütüldü

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 farklı yaklaşım kullanarak bu sorguları tabloya göre çalıştırdım

  • MATCH ... AGAINST
  • LOCATEgibi LOCATE işlevi
  • LIKE

Lütfen farkları not edin

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>

Tüm PunktMatch değerleri 3 1 ve 3 0 değerleri olmalıdır.

Şimdi onları normal olarak sorgulamamı izle

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>

MAÇ kullanarak Tamam .. punkt ile birlikte çalışmıyor. Pankt ne olacak ???

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

mysql>

GROUP BYPankt karşı benim büyük sorgu çalıştıralım

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>

Bu da yanlış çünkü PanktMatch için 3 0 ve 3 1 görmek gerekir.

Başka bir şey denedim

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'a artı işareti ekledim ve farklı sonuçlar aldım. Ne 2 değil 3 ???

MySQL Belgelerine göre , joker karakter hakkında ne söylediğine dikkat edin:

*

Yıldız işareti, kesme (veya joker karakter) operatörü olarak işlev görür. Diğer operatörlerden farklı olarak, etkilenecek kelimeye eklenmelidir. Kelimeler, * işlecinden önceki sözcükle başlıyorsa eşleşir.

Kesme sözcüğü ile bir sözcük belirtilirse, çok kısa (ft_min_word_len ayarından belirlendiği gibi) veya bir parola olsa bile bir boole sorgusundan çıkarılmaz. Bunun nedeni, sözcüğün çok kısa veya bir anahtar sözcük olarak görünmemesi, ancak belgede önekle başlayan bir sözcük biçiminde bulunması gereken bir önek olmasıdır. Diyelim ki ft_min_word_len = 4. Sonra '+ word + *' için yapılan bir arama, '+ word +' için yapılan aramadan daha az satır döndürür:

Eski sorgu olduğu gibi kalır ve belgede hem word hem de * (ile başlayan bir kelime) olmasını gerektirir.

İkinci sorgu + kelimeye dönüştürülür (sadece kelimenin bulunması gerekir). hem çok kısa hem de bir paroladır ve her iki koşul da göz ardı edilmesine neden olmak için yeterlidir.

Buna dayanarak, joker karakter jetonların arkası için geçerlidir, ön için geçerli değildir. Bunun ışığında, çıkış doğru olmalı çünkü 3 punkt'ın başlangıç ​​belirteçlerinden 2'si. Pankt ile aynı hikaye. Bu en azından neden 3 üzerinden 2'yi ve neden daha az satır olduğunu açıklar.


Vay, yatırımınız için çok teşekkürler. Bu, tam metin aramasının beklendiği gibi veya en azından dokümanda belirtildiği gibi çalıştığı anlamına gelir. Ancak bu, tüm tam metin sorununun, belirli bir kelime bölümünü içeren sütunların% 100'ünü bulmaya yardımcı olmayacağını ve bu da onu benim amacım için işe yaramaz hale getirdiğini belirtir. Kesin sonuçlar için LIKE veya LOCALE ile arama yapmam gerekir, ki bu şaşırtıcı bir şekilde her ikisi de daha hızlı görünüyor.
32bitfloat

Neden "Punkten" i buldunuz ve @ 32bitfloat bulamadı ?! Bunun yerine "Treffpunkt" u buldu, ama sen bulmadın. Ve neden "punkt" COUNT(IF(MATCHsorgusunda neden "Pankten" döndürdü anlamıyorum .
mgutt

InnoDB'de neler olduğunu merak ediyorum.
Rick James

Neden var COUNT(…)PunktMatch ve PanktMatch sütunlarda? COUNT(IF(MATCH (meldungstext ) AGAINST ('*pankt*' IN BOOLEAN MODE),1,0))her zaman sonuca ulaşacaktır 1, çünkü bu sayı 1ya 0da sonucudur IF(…).
Quinn Comendant
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.