क्यों पूर्ण-पाठ-खोज LIKE की तुलना में कम पंक्तियाँ देती है


10

मुझे पूर्ण-पाठ-खोज का काम नहीं मिल रहा है, जैसा कि मैं चाहता हूँ, और मुझे परिणामकों में अंतर समझ में नहीं आता है।

उदाहरण कथन:

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

92 पंक्तियाँ देता है। मुझे ऐसी पंक्तियाँ मिलीं, जो मेल खाती हैं, उदाहरण के लिए, "पंकटेन", "ज़ेवेई-पंकटे-वोर्सप्रुंग" और "ट्रेफपंकट" जैसे कॉलम मेलडंगस्टेक्स में।

मैंने "meldungstext" कॉलम पर एक फुलटेक्स्ट-इंडेक्स सेट किया और यह कोशिश की:

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

यह केवल 8 पंक्तियों को लौटाता है। मुझे केवल वही पंक्तियाँ प्राप्त होती हैं जो "पंकट" से मेल खाती हैं या जो शब्द मुझे लगता है कि "पंकट" के रूप में "आई-पंकट" में लिया जाता है।

मैंने तब बूलियन मोड की कोशिश की:

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

44 पंक्तियाँ देता है। मुझे उन पंक्तियों को प्राप्त होता है जिनमें "मेल्वुंगस्टेक्ट" में "ज़ेवी-पंकटे-वोर्सप्रंग" या "ट्रेफपंकट" है, लेकिन "पंकटेन" वाले नहीं।

ऐसा क्यों होता है और मैं कहां-कहां खंड में LIKE '%%' का उपयोग करने से रोकने के लिए एक "पूरी तरह से" पूर्ण-पाठ्य-खोज कार्य सेट कर सकता हूं?


1
यह एक बड़ा +1 का हकदार है क्योंकि इस मुद्दे की वास्तव में जांच नहीं की गई है और FULLTEXT इंडेक्सिंग को अक्सर अनुमति दी जाती है।
रोलैंडमाइसीडीडीबीए

जवाबों:


13

मैं अपने प्रश्न में तीन तार ले लिया और एक मेज के साथ साथ तीन और स्ट्रिंग में जोड़ा साथ panktके बजाय punkt

निम्न को Windows के लिए MySQL 5.5.12 का उपयोग करके निष्पादित किया गया था

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
  • LOCATELOCATE फ़ंक्शन के रूप में
  • 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>

MATCH का उपयोग करके ठीक है .. पंकट के साथ काम नहीं करता है। पंकट के बारे में क्या ???

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। तब '+ शब्द + * के लिए एक खोज संभवतः' + शब्द + 'की खोज की तुलना में कम पंक्तियाँ लौटाएगा:

पूर्व की क्वेरी यथावत बनी हुई है और उसे दस्तावेज़ में मौजूद होने के लिए शब्द और * (शब्द के साथ शुरू होने वाला) दोनों की आवश्यकता होती है।

बाद की क्वेरी + शब्द (केवल शब्द मौजूद होने की आवश्यकता) में बदल जाती है। दोनों बहुत छोटा है और एक स्टॉपवार्ड है, और या तो स्थिति इसे अनदेखा करने के लिए पर्याप्त है।

इसके आधार पर, वाइल्डकार्ड वर्ण टोकन के पीछे के लिए लागू होता है और सामने के लिए नहीं। इसके प्रकाश में, आउटपुट सही होना चाहिए क्योंकि 3 में से 2 पंकट के स्टार्ट टोकन हैं। पंकट के साथ एक ही कहानी। यह कम से कम यह बताता है कि 3 में से 2 क्यों और कम पंक्तियाँ क्यों।


वाह, आपके निवेश के लिए बहुत धन्यवाद। इसका मतलब है कि पूर्ण-पाठ-खोज जासूसी के रूप में काम करती है, या कम से कम जैसा कि कहा जाता है। लेकिन इसमें यह भी कहा गया है कि पूरे पूर्ण-पाठ-अंक में 100% कॉलम खोजने में मदद नहीं मिलेगी, जिसमें दिए गए शब्द-भाग शामिल हैं, जो मेरे उद्देश्यों के लिए बेकार है। सटीक परिणामों के लिए मुझे LIKE या LOCALE के साथ खोज करने की आवश्यकता होगी, जो आश्चर्यजनक रूप से इसके अलावा दोनों अधिक तेज़ लग रहे हैं।
32bitfloat

क्यों आप "Punkten" और @ 32bitfloat नहीं मिला ?! इसके बजाय उसने "ट्रेफपंकट" पाया, लेकिन आपने नहीं किया। और मुझे वास्तव में समझ नहीं आ रहा है कि COUNT(IF(MATCHक्वेरी में "पंकट" ने "पैंकटेन" क्यों लौटाया ।
मैगुटैट

मुझे आश्चर्य है कि InnoDB में क्या होता है।
रिक जेम्स

आपके पास COUNT(…)PunktMatch और PanktMatch कॉलम पर क्यों हैं ? COUNT(IF(MATCH (meldungstext हमेशा परिणाम ) AGAINST ('*pankt*' IN BOOLEAN MODE),1,0))देगा , क्योंकि यह गिनती है या , से परिणाम । 110IF(…)
क्विन कॉमेडियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.