मैंटिकोर सर्च में निर्मित दो उपयोगी टूल्स हैं अपवाद और शब्द रूप, जिनका उपयोग आप खोज की सटीकता और परिशुद्धता में सुधार के लिए कर सकते हैं। उनमें बहुत कुछ समान है, लेकिन महत्वपूर्ण अंतर भी हैं जिन्हें मैं इस लेख में कवर करना चाहूंगा।
टोकनाइजेशन के बारे में
फुल-टेक्स्ट सर्च (जिसे फ्री-टेक्स्ट सर्च भी कहा जाता है) और वाइल्डकार्ड प्रकार की खोज में क्या अंतर है जैसे:
- आमतौर पर ज्ञात
LIKE
ऑपरेटर इस या उस रूप में - या अधिक जटिल रेगुलर एक्सप्रेशन्स
? बेशक बहुत सारे अंतर हैं, लेकिन यह सब प्रारंभिक इनपुट टेक्स्ट के साथ हम क्या करते हैं, इससे शुरू होता है:
- वाइल्डकार्ड सर्च एप्रोच में हम आमतौर पर टेक्स्ट को एक समग्र के रूप में मानते हैं
- जबकि फुल-टेक्स्ट सर्च के क्षेत्र में पहले टेक्स्ट को टोकनाइज करना और फिर प्रत्येक टोकन को एक अलग इकाई के रूप में मानना आवश्यक है
जब आप टेक्स्ट को टोकनाइज करना चाहते हैं तो आपको यह तय करना होगा कि इसे कैसे करें, विशेष रूप से:
- क्या विभाजक और शब्द वर्ण होने चाहिए। सामान्यतः एक विभाजक वह वर्ण होता है जो शब्द के अंदर नहीं आता है, उदाहरण के लिए विराम चिह्न:
.
,,
,?
,!
,-
आदि। - क्या टोकन के अक्षरों का केस बरकरार रखा जाना चाहिए या नहीं। सामान्यतः नहीं क्योंकि यह खोज के लिए बुरा है कि आप कीवर्ड
orange
सेOrange
नहीं ढूंढ पाते।
मैंटिकोर यह सब स्वचालित रूप से करता है। उदाहरण के लिए, टेक्स्ट “What do I have? The list is: a cat, a dog and a parrot.
” को टोकनाइज किया जाता है:
mysql> drop table if exists t;
mysql> create table t(f text);
mysql> call keywords('What do I have? The list is: a cat, a dog and a parrot.', 't');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 1 | what | what |
| 2 | do | do |
| 3 | i | i |
| 4 | have | have |
| 5 | the | the |
| 6 | list | list |
| 7 | is | is |
| 8 | a | a |
| 9 | cat | cat |
| 10 | a | a |
| 11 | dog | dog |
| 12 | and | and |
| 13 | a | a |
| 14 | parrot | parrot |
+------+-----------+------------+
14 rows in set (0.00 sec)
जैसा कि आप देख सकते हैं:
- विराम चिह्न हटा दिए गए थे
- और सभी शब्दों को लोअरकेस कर दिया गया था
समस्या
यहां पहली समस्या आती है: कुछ मामलों में विभाजकों को नियमित शब्द वर्णों के रूप में माना जाता है, उदाहरण के लिए “Is c++ the most powerful language?
” में यह स्पष्ट है कि c++
एक अलग शब्द है। लोगों के लिए यह समझना आसान है, लेकिन फुल-टेक्स्ट सर्च एल्गोरिथम के लिए नहीं, क्योंकि यह प्लस चिह्न को देखता है, इसे अपनी शब्द वर्णों की सूची में नहीं पाता और इसे टोकन से हटा देता है, इसलिए आप इस प्रकार समाप्त करते हैं:
mysql> drop table if exists t;
mysql> create table t(f text);
mysql> call keywords('Is c++ the most powerful language?', 't');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 1 | is | is |
| 2 | c | c |
| 3 | the | the |
| 4 | most | most |
| 5 | powerful | powerful |
| 6 | language | language |
+------+-----------+------------+
6 rows in set (0.00 sec)
ठीक है, लेकिन समस्या क्या है?
समस्या यह है कि इस टोकनाइजेशन के बाद यदि आप c#
के लिए खोज करते हैं, तो आपको उपरोक्त वाक्य मिल जाएगा:
mysql> drop table if exists t;
mysql> create table t(f text);
mysql> insert into t values(0,'Is c++ the most powerful language?');
mysql> select highlight() from t where match('c#');
+-------------------------------------------+
| highlight() |
+-------------------------------------------+
| Is <b>c</b>++ the most powerful language? |
+-------------------------------------------+
1 row in set (0.01 sec)
ऐसा इसलिए होता है क्योंकि c#
को भी केवल c
में टोकनाइज किया जाता है और फिर खोज क्वेरी का c
दस्तावेज़ के c
से मेल खाता है और आपको यह मिलता है।
समाधान क्या है? कुछ विकल्प हैं। पहला जो शायद दिमाग में आता है:
ठीक है, मैं + और # को शब्द वर्णों की सूची में क्यों नहीं डालता?
यह एक अच्छा और उचित प्रश्न है। आइए कोशिश करें।
mysql> drop table if exists t;
mysql> create table t(f text) charset_table='non_cjk,+,#';
mysql> call keywords('Is c++ the most powerful language?', 't');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 1 | is | is |
| 2 | c++ | c++ |
| 3 | the | the |
| 4 | most | most |
| 5 | powerful | powerful |
| 6 | language | language |
+------+-----------+------------+
6 rows in set (0.00 sec)
यह काम करता है, लेकिन सूची में +
तुरंत अन्य शब्दों और खोजों को प्रभावित करना शुरू कर देता है, उदाहरण के लिए:
mysql> drop table if exists t;
mysql> create table t(f text) charset_table='non_cjk,+,#';
mysql> call keywords('What is 2+2?', 't');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 1 | what | what |
| 2 | is | is |
| 3 | 2+2 | 2+2 |
+------+-----------+------------+
3 rows in set (0.00 sec)
आप चाहते थे कि c++
एक अलग शब्द हो, लेकिन 2+2
नहीं, है ना?
ठीक है, तो हम क्या कर सकते हैं?
c++
को विशेष तरीके से मानने के लिए आप इसे एक अपवाद बना सकते हैं।
अपवाद
तो, अपवाद
(जिन्हें पर्यायवाची भी कहा जाता है) एक या अधिक शब्दों को एक एकल कीवर्ड में मैप करने की अनुमति देते हैं (उन शब्दों सहित जिनमें ऐसे वर्ण हैं जो सामान्यतः बाहर रखे जाते हैं)।
आइए c++
को एक अपवाद बनाएं इसे एक अपवाद फ़ाइल में डालकर:
➜ ~ cat /tmp/exceptions
c++ => c++
और फ़ाइल का उपयोग तब करें जब हम टेबल बनाते हैं:
mysql> drop table if exists t;
mysql> create table t(f text) exceptions='/tmp/exceptions';
mysql> call keywords('Is c++ the most powerful language? What is 2+2?', 't');
+------+-----------+------------+
| qpos | tokenized | normalized |
+------+-----------+------------+
| 1 | है | है |
| 2 | c++ | c++ |
| 3 | जो | जो |
| 4 | सबसे | सबसे |
| 5 | शक्तिशाली | शक्तिशाली |
| 6 | भाषा | भाषा |
| 7 | क्या | क्या |
| 8 | है | है |
| 9 | 2 | 2 |
| 10 | 2 | 2 |
+------+-----------+------------+
10 पंक्तियाँ सेट में (0.01 सेकंड)
याहू, c++
अब एक अलग शब्द है और प्लस साइन नहीं खो गए हैं, और 2+2
के साथ भी सब ठीक है।
आपको अपवादों के बारे में याद रखने के लिए जो चीज़ें हैं, वे हैं कि अपवाद बहुत मूर्ख हैं, बिल्कुल भी स्मार्ट नहीं हैं, वे बिल्कुल करते हैं जो आप उनसे करने के लिए कहते हैं और कुछ नहीं। विशेष रूप से:
- वे केस नहीं बदलते
- यदि आप गलती से डबल स्पेस डालते हैं, तो वे इसे एकल स्पेस में नहीं बदलते
और इसी तरह। वे सचमुच आपके इनपुट को बाइट्स के एक ऐरे के रूप में मानते हैं।
उदाहरण के लिए, लोग c++
को छोटे और बड़े दोनों अक्षरों में लिखते हैं। आइए ऊपर दिए गए अपवाद को बड़े अक्षर के साथ आजमाएं?
mysql> यदि 't' टेबल को हटाएं;
mysql> 't'(f पाठ) को बनाएँ यदि मौजूद नहीं है; अपवाद='/tmp/exceptions';
mysql> कीवर्ड का आह्वान करें('क्या C++ सबसे शक्तिशाली भाषा है? `c++` के बारे में कैसे?','t');
+------+-----------+------------+
| qpos | टोकनाइज़ किया | सामान्यीकृत |
+------+-----------+------------+
| 1 | है | है |
| 2 | c | c |
| 3 | जो | जो |
| 4 | सबसे | सबसे |
| 5 | शक्तिशाली | शक्तिशाली |
| 6 | भाषा | भाषा |
| 7 | क्या | क्या |
| 8 | है | है |
| 9 | 2 | 2 |
| 10 | 2 | 2 |
+------+-----------+------------+
10 पंक्तियाँ सेट में (0.00 सेकंड)
अरे, C++
को सिर्फ c
के रूप में टोकनाइज़ किया गया, क्योंकि अपवाद c++
(छोटे अक्षर में) है, न कि C++
(बड़े अक्षर में)।
लेकिन क्या आपने देखा कि अपवाद में तत्वों का एक जोड़ा होता है, न कि एकल: c++ => c++
। बाईं ओर वह भाग है जो टेक्स्ट में अपवादों के एल्गोरिदम को ट्रिगर करता है, दाहिनी ओर एक परिणामस्वरूप टोकन होता है। आइए C++
को c++
के लिए मैपिंग जोड़ने का प्रयास करें?
➜ ~ कैट /tmp/exceptions
c++ => c++
C++ => c++
mysql> यदि 't' टेबल को हटाएं;
mysql> 't'(f पाठ) को बनाएँ यदि मौजूद नहीं है; अपवाद='/tmp/exceptions';
mysql> कीवर्ड का आह्वान करें('क्या C++ सबसे शक्तिशाली भाषा है? `c++` के बारे में कैसे?','t');
+------+-----------+------------+
| qpos | टोकनाइज़ किया | सामान्यीकृत |
+------+-----------+------------+
| 1 | है | है |
| 2 | c++ | c++ |
| 3 | जो | जो |
| 4 | सबसे | सबसे |
| 5 | शक्तिशाली | शक्तिशाली |
| 6 | भाषा | भाषा |
| 7 | कैसे | कैसे |
| 8 | के बारे में | के बारे में |
| 9 | c++ | c++ |
+------+-----------+------------+
9 पंक्तियाँ सेट में (0.00 सेकंड)
अच्छा है, अब यह फिर से ठीक है, क्योंकि C++
और c++
दोनों को टोकन c++
में टोकनाइज़ किया गया है। बहुत संतोषजनक।
अपवादों के अन्य अच्छे उदाहरण क्या हैं:
AT&T => AT&T
औरat&t => AT&T
।M&M's => M&M's
औरm&m's => M&M's
औरM&m's => M&M's
U.S.A. => USA
औरUS => USA
बुरे उदाहरण क्या हैं?
us => USA
, क्योंकि हम नहीं चाहते कि प्रत्येकus
USA
बन जाए।
तो अपवादों के साथ एक नियम यह है:
यदि एक शब्द में विशेष अक्षर शामिल हैं और यह सामान्य रूप से पाठ और खोज क्वेरी में लिखा जाता है - इसे एक अपवाद बनाएं।
समानार्थी
Manticore खोज उपयोगकर्ता अक्सर अपवाद
को समानार्थी कहते हैं, क्योंकि उनके लिए एक और उपयोग केस बस विशेष वर्ण और अक्षर के मामले को बनाए रखना नहीं है, बल्कि पूरी तरह से अलग तरह से लिखे गए शब्दों को एक ही टोकन पर मैप करना है, उदाहरण के लिए:
MS Windows => ms windows
Microsoft Windows => ms windows
यह महत्वपूर्ण क्यों है? क्योंकि यह आसानी से Microsoft Windows
के दस्तावेजों को MS Windows
द्वारा ढूंढने में सक्षम बनाता है और इसके विपरीत।
उदाहरण:
mysql> यदि 't' टेबल को हटाएं;
mysql> 't'(f पाठ) को बनाएँ यदि मौजूद नहीं है; अपवाद='/tmp/exceptions';
mysql> 't' में मान डालें(0, 'Microsoft Windows पहले ऑपरेटिंग सिस्टम में से एक है');
mysql> `MS Windows` से मिलान करते हुए `t` से * का चयन करें;
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976139 | Microsoft Windows पहले ऑपरेटिंग सिस्टम में से एक है |
+---------------------+---------------------------------------------------------+
1 पंक्ति सेट में (0.00 सेकंड)
तो पहली नज़र में यह ठीक लग रहा है, लेकिन इसके बारे में और सोचते हुए और यह याद रखते हुए कि अपवाद केस और बाइट संवेदनशील होते हैं, आप अपने आप से पूछ सकते हैं: “क्या लोग MicroSoft windows
, MS WINDOWS
, microsoft Windows
आदि नहीं लिख सकते?”
हाँ, वे लिख सकते हैं। इसलिए यदि आप इसके लिए अपवाद का उपयोग करना चाहते हैं, तो उस स्थिति के लिए तैयार रहें जो गणित में संयोजक विस्फोट के रूप में जाना जाता है।
यह बिल्कुल अच्छा नहीं लगता। हम इसके बारे में क्या कर सकते हैं?
शब्द रूप
एक और उपकरण जो अपवादों के समान है वह है शब्द रूप
। अपवादों के विपरीत, शब्द रूप आने वाले पाठ को टोकनाइज़ करने के बाद लागू होते हैं। इसलिए वे:
- केस अव्यवस्थित होते हैं (जब तक कि आपका
charset_table
केस संवेदनशीलता को सक्षम नहीं करता) - विशेष वर्णों की परवाह नहीं करते
वे मूल रूप से एक शब्द को दूसरे से बदलने की अनुमति देते हैं। सामान्य रूप से, इसका उपयोग विभिन्न शब्द रूपों को एक सामान्य रूप में लाने के लिए किया जाएगा। उदाहरण के लिए, सभी वैरिएंट जैसे “walks”, “walked”, “walking” को सामान्य रूप “walk” में सामान्यीकृत करने के लिए:
➜ ~ कैट /tmp/wordforms
walks => walk
walked => walk
walking => walk
mysql> यदि 't' टेबल को हटाएं;
mysql> 't'(f पाठ) को बनाएँ यदि मौजूद नहीं है; शब्द रूप='/tmp/wordforms';
mysql> 'walks _WaLkeD! walking' को कॉल करें('t');
+------+-----------+------------+
| qpos | टोकनाइज़ किया | सामान्यीकृत |
+------+-----------+------------+
| 1 | walks | walk |
| 2 | walked | walk |
| 3 | walking | walk |
+------+-----------+------------+
3 पंक्तियाँ सेट में (0.00 सेकंड)
As you can see all the 3 words were converted to just walk
and, note, the 2nd word _WaLkeD!
even being very deformed was also normalized fine. Do you see where I’m going with this? Yes, the MS Windows
example. Let’s test if the wordforms can be useful to solve that issue.
Let’s put just 2 lines to the wordforms file:
➜ ~ cat /tmp/wordforms
ms windows => ms windows
microsoft windows => ms windows
and populate the table with a few documents:
mysql> drop table if exists t;
mysql> create table t(f text) wordforms='/tmp/wordforms';
mysql> insert into t values(0, 'Microsoft Windows is one of the first operating systems'), (0, 'porch windows'),(0, 'Windows are rolled down');
mysql> select * from t;
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976166 | Microsoft Windows is one of the first operating systems |
| 1514841286668976167 | porch windows |
| 1514841286668976168 | Windows are rolled down |
+---------------------+---------------------------------------------------------+
3 rows in set (0.00 sec)
Let’s now try various queries:
mysql> select * from t where match('MS Windows');
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976166 | Microsoft Windows is one of the first operating systems |
+---------------------+---------------------------------------------------------+
1 row in set (0.00 sec)
✅ MS Windows
finds Microsoft Windows
fine.
mysql> select * from t where match('ms WINDOWS');
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976166 | Microsoft Windows is one of the first operating systems |
+---------------------+---------------------------------------------------------+
1 row in set (0.01 sec)
✅ ms WINDOWS
works fine too.
mysql> select * from t where match('mIcRoSoFt WiNdOwS');
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976166 | Microsoft Windows is one of the first operating systems |
+---------------------+---------------------------------------------------------+
1 row in set (0.00 sec)
✅ And even mIcRoSoFt WiNdOwS
finds the same document.
mysql> select * from t where match('windows');
+---------------------+---------------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------------+
| 1514841286668976166 | Microsoft Windows is one of the first operating systems |
| 1514841286668976167 | porch windows |
| 1514841286668976168 | Windows are rolled down |
+---------------------+---------------------------------------------------------+
3 rows in set (0.00 sec)
✅ Just basic windows
finds all the documents.
So indeed, wordforms
helps to solve the issue.
The rule of thumb with the wordforms is:
Use wordforms for words and phrases that can be written in different forms and don’t contain special characters.
Floor & Decor
Let’s take a look at another example: we want to improve search for the brand name Floor & Decor
. We can assume people can write this name in the following forms:
Floor & Decor
Floor & decor
floor & decor
Floor and Decor
floor and decor
and other letter capitalization combinations.
Also:
Floor & Decor Holdings
Floor & Decor Holdings, inc.
and, again, various combinations with different letter capitalized.
Now that we know how exceptions
and wordforms
work what do we do to cover this brand name?
First of all we can easily notice that the canonical brand name is Floor & Decor
, i.e. it includes a special character which is normally considered a word separator, so should we use exceptions
? But the name is long and can be written in many ways. If we use exceptions
we can end up with a huge list of all the combinations. Moreover there are extended forms Floor & Decor Holdings
and Floor & Decor Holdings, inc.
which can make the list even longer.
The most optimal solution in this case is to just use wordforms
like this:
➜ ~ cat /tmp/wordforms
floor & decor => fnd
floor and decor => fnd
floor & decor holdings => fnd
floor and decor holdings => fnd
floor & decor holdings inc => fnd
floor and decor holdings inc => fnd
Why does it include &
? Actually you can skip it:
floor decor => fnd
floor and decor => fnd
floor decor holdings => fnd
floor and decor holdings => fnd
floor decor holdings inc => fnd
floor and decor holdings inc => fnd
because wordforms
anyway ignores non-word characters, but just for the sake of ease of reading it was left.
As a result you’ll get each combination tokenized as fnd
which will be our shortkey for this brand name.
mysql> drop table if exists t; create table t(f text) wordforms='/tmp/wordforms';
mysql> call keywords('Floor & Decor', 't')
+------+-------------+------------+
| qpos | tokenized | normalized |
+------+-------------+------------+
| 1 | floor decor | fnd |
+------+-------------+------------+
1 row in set (0.00 sec)
mysql> call keywords('फ्लोर और डेकोर', 't')
+------+-----------------+------------+
| qpos | tokenized | normalized |
+------+-----------------+------------+
| 1 | फ्लोर और डेकोर | fnd |
+------+-----------------+------------+
1 row in set (0.00 sec)
mysql> call keywords('फ्लोर & डेकोर होल्डिंग्स', 't')
+------+----------------------+------------+
| qpos | tokenized | normalized |
+------+----------------------+------------+
| 1 | फ्लोर डेकोर होल्डिंग्स | fnd |
+------+----------------------+------------+
1 row in set (0.00 sec)
mysql> call keywords('फ्लोर & डेकोर होल्डिंग्स इंक।', 't')
+------+--------------------------+------------+
| qpos | tokenized | normalized |
+------+--------------------------+------------+
| 1 | फ्लोर डेकोर होल्डिंग्स इंक | fnd |
+------+--------------------------+------------+
1 row in set (0.00 sec)
क्या यह उत्तम अंतिम समाधान है? दुर्भाग्यवश नहीं, जैसे इस क्षेत्र में कई अन्य चीजें। यहां हमेशा कुछ दुर्लभ मामले होते हैं और इस मामले में भी। उदाहरण के लिए:
mysql> drop table if exists t; create table t(f text) wordforms='/tmp/wordforms';
mysql> insert into t values(0,'यह 2nd फ्लोर पर स्थित है। डेकोर भी अच्छा है');
mysql> select * from t where match('फ्लोर & डेकोर होल्डिंग्स');
+---------------------+---------------------------------------------------+
| id | f |
+---------------------+---------------------------------------------------+
| 1514841286668976231 | यह 2nd फ्लोर पर स्थित है। डेकोर भी अच्छा है |
+---------------------+---------------------------------------------------+
1 row in set (0.00 sec)
हम यहां देख सकते हैं कि फ्लोर & डेकोर होल्डिंग्स
उस दस्तावेज़ को ढूंढता है जिसमें पहले वाक्य के अंत में फ्लोर
है और अगला वाक्य डेकोर
से शुरू होता है। ऐसा इसलिए होता है क्योंकि फ्लोर। डेकोर
भी fnd
में टोकनाइज़ किया जाता है क्योंकि हम केवल wordforms
का उपयोग करते हैं जो पत्र के केस और विशेष अक्षरों के प्रति संवेदनशील नहीं हैं:
mysql> call keywords('फ्लोर। डेकोर', 't');
+------+-------------+------------+
| qpos | tokenized | normalized |
+------+-------------+------------+
| 1 | फ्लोर डेकोर | fnd |
+------+-------------+------------+
1 row in set (0.00 sec)
गलत मिलान अच्छा नहीं है। इस विशेष समस्या को हल करने के लिए हम Manticore की कार्यक्षमता का उपयोग कर सकते हैं वाक्यों और पैरा की पहचान करने के लिए .
अब अगर हम इसे सक्षम करते हैं तो हम देख सकते हैं कि दस्तावेज़ अब कीवर्ड के लिए कोई मिलान नहीं है:
mysql> drop table if exists t; create table t(f text) wordforms='/tmp/wordforms' index_sp='1';
mysql> insert into t values(0,'यह 2nd फ्लोर पर स्थित है। डेकोर भी अच्छा है');
mysql> select * from t where match('फ्लोर & डेकोर होल्डिंग्स');
Empty set (0.00 sec)
क्योंकि:
फ्लोर & डेकोर
, जैसा कि हम याद करते हैं,wordforms
द्वाराfnd
में परिवर्तित होता हैindex_sp='1'
पाठ को वाक्यों में विभाजित करता है- विभाजन के बाद
फ्लोर।
औरडेकोर
अलग-अलग वाक्यों में समाप्त होते हैं - और इसलिए अब इसकी सभी मूल रूपों से मेल नहीं रखते हैं
निष्कर्ष
Manticore के अपवादों और वर्डफॉर्म्स शक्तिशाली उपकरण हैं जो आपकी खोज को विस्तारित करने में मदद कर सकते हैं, विशेष रूप से छोटे शब्दों के लिए याददाश्त और सटीकता में सुधार करने के लिए, जिनमें विशेष अक्षर बनाए रखने चाहिए और लंबे शब्दों के लिए जिन्हें एक दूसरे से समकक्ष बनाना चाहिए। लेकिन आपको Manticore को मदद करनी होगी, क्योंकि यह आपके लिए नामों का निर्णय नहीं ले सकता।
इस लेख को पढ़ने के लिए धन्यवाद!