एफटीएस डॉट्स के साथ ईमेल के साथ अपेक्षा के अनुरूप काम नहीं करता है


9

हम एक बड़ी प्रणाली के एक भाग के रूप में खोज विकसित कर रहे हैं।

हम Microsoft SQL Server 2014 - 12.0.2000.8 (X64) Standard Edition (64-bit)इस सेटअप के साथ:

CREATE TABLE NewCompanies(
    [Id] [uniqueidentifier] NOT NULL,
    [Name] [nvarchar](400) NOT NULL,
    [Phone] [nvarchar](max) NULL,
    [Email] [nvarchar](max) NULL,
    [Contacts1] [nvarchar](max) NULL,
    [Contacts2] [nvarchar](max) NULL,
    [Contacts3] [nvarchar](max) NULL,
    [Contacts4] [nvarchar](max) NULL,
    [Address] [nvarchar](max) NULL,
    CONSTRAINT PK_Id PRIMARY KEY (Id)
);
  1. Phone एक संरचित अल्पविराम से अलग किया गया अंक स्ट्रिंग है "77777777777, 88888888888"
  2. Emailकॉमा के साथ संरचित ईमेल स्ट्रिंग है "email1@gmail.com, email2@gmail.com"(या बिना कॉमा के जैसे सभी "email1@gmail.com")
  3. Contacts1, Contacts2, Contacts3, Contacts4ऐसे टेक्स्ट फ़ील्ड हैं जहां उपयोगकर्ता निशुल्क रूप में संपर्क विवरण निर्दिष्ट कर सकते हैं। जैसा "John Smith +1 202 555 0156"या "Bob, +1-999-888-0156, bob@company.com"। इन क्षेत्रों में वे ईमेल और फ़ोन शामिल हो सकते हैं जिन्हें हम आगे खोजना चाहते हैं।

यहाँ हम फुल-टेक्स्ट स्टफ बनाते हैं

-- FULL TEXT SEARCH
CREATE FULLTEXT CATALOG NewCompanySearch AS DEFAULT;  
CREATE FULLTEXT INDEX ON NewCompanies(Name, Phone, Email, Contacts1, Contacts2, Contacts3, Contacts4, Address)
KEY INDEX PK_Id

यहाँ एक डेटा नमूना है

INSERT INTO NewCompanies(Id, Name, Phone, Email, Contacts1, Contacts2, Contacts3, Contacts4) 
VALUES ('7BA05F18-1337-4AFB-80D9-00001A777E4F', 'PJSC Azimuth', '79001002030, 78005005044', 'regular@hotmail.com, s.m.s@gmail.com', 'John Smith', 'Call only at weekends +7-999-666-22-11', NULL, NULL)

वास्तव में हमारे पास लगभग 100 हजारों ऐसे रिकॉर्ड हैं।

हम उम्मीद करते हैं कि उपयोगकर्ता "@ gmail.com" जैसे ईमेल का एक हिस्सा निर्दिष्ट कर सकते हैं और यह किसी भी Email, Contacts1, Contacts2, Contacts3, Contacts4क्षेत्र में जीमेल ईमेल पते के साथ सभी पंक्तियों को वापस करना चाहिए ।

फोन नंबर के लिए भी यही। उपयोगकर्ता "70283" जैसे पैटर्न की खोज कर सकते हैं और एक क्वेरी में इन अंकों के साथ फोन वापस करना चाहिए। यह मुफ़्त फॉर्म Contacts1, Contacts2, Contacts3, Contacts4फ़ील्ड के लिए भी है जहाँ हमें संभवतः खोज से पहले सभी लेकिन अंकों और अंतरिक्ष वर्णों को हटा देना चाहिए।

हम LIKEखोज के लिए उपयोग करते थे जब हमारे पास लगभग 1500 रिकॉर्ड थे और यह ठीक काम करता था लेकिन अब हमारे पास बहुत सारे रिकॉर्ड हैं और LIKEपरिणाम प्राप्त करने के लिए खोज अनंत है।

इस प्रकार हम वहां से डेटा प्राप्त करने का प्रयास करते हैं:

SELECT * FROM NewCompanies WHERE CONTAINS((Email, Contacts1, Contacts2, Contacts3, Contacts4), '"s.m.s@gmail.com*"') -- this doesn't get the row
SELECT * FROM NewCompanies WHERE CONTAINS((Phone, Contacts1, Contacts2, Contacts3, Contacts4), '"6662211*"') -- doesn't get anything
SELECT * FROM NewCompanies WHERE CONTAINS(Name, '"zimuth*"') -- doesn't get anything

5
आपके सभी कॉलम nvarchar(MAX)यहां क्यों हैं ? मैंने कभी किसी के बारे में नहीं सुना या उनसे मुलाकात नहीं की, जिसका नाम 1 बिलियन ~ वर्ण लंबा है। और, इस उत्तर के अनुसार , एक ईमेल पता 254 वर्णों का नहीं हो सकता है; तो आप भी वहाँ 1 बिलियन ~ व्यर्थ अक्षर हैं।
लारनु

2
ऐसा लगता है जैसे आप पूर्ण-पाठ खोज के शब्द ब्रेकर से लड़ रहे हैं। वर्ण शब्द ब्रेकर @gmail.comहोने के कारण आपको खोज शब्द के रूप में उपयोग करने की संभावना नहीं है @। दूसरे शब्दों में, आप SQL सर्वर के संस्करण के आधार में, सूचकांक में शब्दों के लिए user@gmail.comया तो (ए) हो जाएगा user, gmailऔर comया (बी) user, user@gmail.com, gmailऔर com। REF: व्यवहार पूर्ण-पाठ खोज में परिवर्तन
AlwaysLearning

1
"लेकिन मैं उन क्षेत्रों में ईमेल और फोन के अलावा कुछ भी नहीं खोजना चाहता हूं" फिर उन्हें एक उपयुक्त कॉलम में संग्रहीत किया जाना चाहिए, जैसे मैंने पहले कहा था। आपके पास उस डेटा के लिए कॉलम हैं, जिन्हें सामान्यीकृत किया जाना चाहिए। शब्द ब्रेकर उदाहरण / डेटाबेस स्तर पर सेट किए जाते हैं। इसलिए इसे हटाना एक महत्वपूर्ण परिवर्तन होगा .
लारनु

1
आप या तो सभी फोन, ईमेल आदि के लिए 1-एम के लिए तालिकाओं को सामान्य करना चाहते हैं। रिकॉर्ड दूसरा विकल्प कॉलम को विभाजित करने के लिए है (string_split का उपयोग करें (ईमेल, ','), बाहरी आवेदन के संयोजन में। आपको लागू करना होगा। उपयोगकर्ता के पास जितने ईमेल हो सकते हैं उन पर एक सैद्धांतिक सीमा निर्दिष्ट करें। फिर इस तरह से एक खोज लिखें: SELECT * FROM NewCompanies WHERE Id IN (SELECT ID from .... where MyOuterApply.EmailCol1 LIKE '%'+@SearchString+'%') OR Id IN (SELECT ID from .... where MyOuterApply.EmailCol2 LIKE '%'+@SearchString+'%')प्रत्येक फ़ील्ड पर लगभग पांच अलग-अलग इंडेक्स बनाएं और प्राथमिक कुंजी शामिल करें।
स्टारबोन

2
@ TheDudeWithHat नहीं जा रहा है, इसका मतलब यह नहीं है कि नहीं होना चाहिए। ओपी के पास समस्या है कि वे सामान्यीकरण की कमी के कारण हैं।
लारनु

जवाबों:


2

वास्तव में अनुरोध

चुनें [...] CONTAINS ([...], "6662211 *" "- कुछ भी नहीं मिलता है

के खिलाफ 'Call only at weekends +7-999-666-22-11' और

चयन [...] का नाम (नाम, "" zimuth * "") - कुछ भी नहीं मिलता है

विरुद्ध 'PJSC Azimuth'

उम्मीद के मुताबिक काम करेंउपसर्ग शब्द
देखें । क्योंकि न एक है उपसर्ग के रूप में अच्छी तरह है एक नहीं उपसर्ग की6662211*+7-999-666-22-11zimuth*Azimuth

से संबंधित

चुनें [...] CONTAINS ([...], "sms@gmail.com*" ") - यह पंक्ति प्राप्त नहीं करता है

यह शायद के रूप में शब्द तोड़ने की वजह से है alwayslearning टिप्पणी में बताया। शब्द तोड़ने वाले देखें

मुझे नहीं लगता कि पूर्ण-पाठ खोज आपके कार्य के लिए लागू है।

LTS ऑपरेटर के लिए उपयोग किए जाने वाले सटीक कार्यों में FTS का उपयोग क्यों किया जाता है? यदि LIKE प्रश्नों के लिए एक बेहतर इंडेक्स प्रकार थे ... तो बेहतर इंडेक्स प्रकार होगा , न कि पूरी तरह से अलग तकनीक और वाक्यविन्यास।
और किसी भी तरह से यह आपको "6662211*""666 कुछ मनमाना चार 22 कुछ मनमाना चार 11" के खिलाफ मैच करने में मदद करेगा ।
पूर्ण पाठ खोज regex-es के बारे में नहीं है (और "6662211*"नौकरी के लिए एक सही अभिव्यक्ति भी नहीं है - यह "कुछ मनमाना चार" भाग के बारे में कुछ भी नहीं है) यह समानार्थक शब्द, शब्द रूपों आदि के बारे में है।

लेकिन क्या प्रभावी रूप से सबस्ट्रिंग की खोज करना संभव है?

हाँ यही है। अपने स्वयं के खोज इंजन को लिखने के रूप में ऐसी संभावनाओं को छोड़कर, हम भीतर क्या कर सकते हैं SQL?

सबसे पहले - यह आपके डेटा को साफ करने के लिए एक जरूरी है! यदि आप उपयोगकर्ताओं को उनके द्वारा दर्ज किए गए सटीक तारों पर वापस लौटना चाहते हैं

उपयोगकर्ता निशुल्क रूप में संपर्क विवरण निर्दिष्ट कर सकते हैं

... आप उन्हें बचा सकते हैं ... और उन्हें साथ छोड़ सकते हैं।
फिर आपको मुफ्त फॉर्म टेक्स्ट (यह ईमेल और फोन नंबर के लिए इतना कठिन नहीं है) से डेटा निकालने की जरूरत है और डेटा को कुछ औपचारिक रूप में सहेजना होगा। ईमेल के लिए, केवल एक चीज जो आपको वास्तव में करने की आवश्यकता है - उन्हें सभी लोअरकेस या अपरकेस (कोई फर्क नहीं पड़ता), और शायद तब @गाने पर विभाजित करें । लेकिन फोन नंबरों में आपको केवल अंक छोड़ने की आवश्यकता होती है
... (और फिर आप उन्हें संख्याओं के रूप में भी संग्रहीत कर सकते हैं । यह आपके स्थान और समय को बचा सकता है। लेकिन खोज अलग होगी ... अभी के लिए और अधिक सरल में गोता लगाएँ। और तार का उपयोग कर सार्वभौमिक समाधान।)

जैसा कि मैथ्यूबैकर ने उल्लेख किया है कि आप प्रत्ययों की एक तालिका बना सकते हैं। तब तुम ऐसे ही खोज सकते हो

SELECT DISTINCT * FROM NewCompanies JOIN Sufficies ON NewCompanies.Id = Sufficies.Id WHERE Sufficies.sufficies LIKE 'some text%'

आपको वाइल्डकार्ड %को अंत में रखना चाहिए । या प्रत्यय तालिका से कोई लाभ नहीं होगा।

उदाहरण के लिए फोन नंबर लें

+ 7-999-666-22-11

इसके बाद हम इसमें कचरे के ढेर से छुटकारा पा लेते हैं, इसमें 11 अंक होंगे। इसका मतलब है कि हमें एक फोन नंबर के लिए 11 प्रत्ययों की आवश्यकता होगी

           1
          11
         211
        2211
       62211
      662211
     6662211
    96662211
   996662211
  9996662211
 79996662211

तो इस समाधान के लिए अंतरिक्ष जटिलता रैखिक है ... इतना बुरा नहीं है, मैं कहूंगा ... लेकिन प्रतीक्षा करें यह रिकॉर्ड की संख्या में जटिलता है। लेकिन प्रतीकों में ... हमें N(N+1)/2सभी प्रत्ययों को संग्रहीत करने के लिए प्रतीकों की आवश्यकता है - जो कि द्विघात जटिलता है ... अच्छा नहीं है ... लेकिन अगर आपके पास अब 100 000रिकॉर्ड हैं और निकट भविष्य में लाखों की योजना नहीं है - तो आप इसके साथ जा सकते हैं समाधान।

क्या हम अंतरिक्ष की जटिलता को कम कर सकते हैं?

मैं केवल विचार का वर्णन करूंगा, इसे लागू करने से कुछ प्रयास होंगे। और शायद हमें इसकी सीमाओं को पार करना होगाSQL

मान लें कि आपके पास इसमें 2 पंक्तियाँ हैं NewCompaniesऔर इसमें 2 तरह के मुफ़्त फॉर्म टेक्स्ट हैं:

    aaaaa
    11111

प्रत्यय तालिका कितनी बड़ी होनी चाहिए? जाहिर है, हमें केवल 2 रिकॉर्ड चाहिए।

एक और उदाहरण लेते हैं। इसके अलावा 2 पंक्तियों, 2 मुक्त पाठ तार के लिए खोज करने के लिए। लेकिन अब यह है:

    aa11aa
    cc11cc

आइए देखें कि अब हमें कितने प्रत्ययों की आवश्यकता है:

         a // no need, LIKE `a%`  will match against 'aa' and 'a11aa' and 'aa11aa'
        aa // no need, LIKE `aa%` will match against 'aa11aa'
       1aa
      11aa
     a11aa
    aa11aa
         c // no need, LIKE `c%`  will match against 'cc' and 'c11cc' and 'cc11cc'
        cc // no need, LIKE `cc%` will match against 'cc11cc'
       1cc
      11cc
     c11cc
    cc11cc

इतना बुरा नहीं, लेकिन इतना अच्छा भी नहीं।

इसके अलावा हम क्या कर सकते हैं?

मान लीजिए, उपयोगकर्ता "c11"खोज क्षेत्र में प्रवेश करता है। फिर सफल होने के लिए LIKE 'c11%'' c11 cc' प्रत्यय की जरूरत है । लेकिन अगर "c11"हम खोजने के बजाय पहले खोजते हैं "c%", तो फिर "c1%"और इसी तरह? पहली खोज से केवल एक पंक्ति दी जाएगी NewCompanies। और बाद की खोजों की कोई आवश्यकता नहीं होगी। और हम कर सकते हैं

       1aa // drop this as well, because LIKE '1%' matches '11aa'
      11aa
     a11aa // drop this as well, because LIKE 'a%' matches 'aa11aa'
    aa11aa
       1cc // same here
      11cc
     c11cc // same here
    cc11cc

और हम केवल 4 प्रत्ययों के साथ समाप्त होते हैं

      11aa
    aa11aa
      11cc
    cc11cc

मैं यह नहीं कह सकता कि इस मामले में अंतरिक्ष की जटिलता क्या होगी, लेकिन ऐसा लगता है कि यह स्वीकार्य होगा।


1

इस तरह के मामलों में पूर्ण पाठ खोज आदर्श से कम है। मैं उसी नाव में था जैसा आप हैं। जैसे खोज बहुत धीमी होती है, और पूर्ण पाठ खोज उन शब्दों को खोजती है जो किसी शब्द से शुरू होते हैं बजाय एक शब्द के।

हमने कई समाधानों की कोशिश की, एक शुद्ध SQL विकल्प पूर्ण पाठ खोज के अपने संस्करण का निर्माण करना है, विशेष रूप से एक उल्टे सूचकांक खोज में। हमने यह कोशिश की, और यह सफल रहा, लेकिन बहुत जगह ले ली। हमने आंशिक खोज शब्दों के लिए एक द्वितीयक होल्डिंग तालिका बनाई, और उस पर पूर्ण पाठ अनुक्रमण का उपयोग किया। हालाँकि इसका मतलब है कि हमने एक ही चीज़ की कई प्रतियाँ संग्रहीत की हैं। उदाहरण के लिए हमने "longword" को Longword, ongword, ngword, gword .... आदि के रूप में संग्रहीत किया है। इसलिए कोई भी निहित वाक्यांश हमेशा अनुक्रमित शब्द के प्रारंभ में होगा। एक भयावह समाधान, खामियों से भरा, लेकिन यह काम किया।

फिर हमने लुकअप के लिए एक अलग सर्वर होस्ट करने पर ध्यान दिया। Googling Lucene और elastisearch आपको शेल्फ पैकेजों के बारे में अच्छी जानकारी देगा।

आखिरकार, हमने अपना स्वयं का घर खोज इंजन विकसित किया, जो साइड एसक्यूएल के साथ चलता है। इससे हमें ध्वन्यात्मक खोजों (डबल मेटाफोन) को लागू करने और फिर प्रासंगिकता स्थापित करने के लिए साइड साउंडेक्स के साथ लेवेंशेटिन गणनाओं का उपयोग करने की अनुमति मिली है। बहुत सारे समाधानों के लिए ओवरकिल, लेकिन हमारे उपयोग के मामले में प्रयास के लायक। हमारे पास अब भी क्यूडा खोजों के लिए एनवीडिया जीपीयू का लाभ उठाने का एक विकल्प है, लेकिन यह सिरदर्द और नींद की रातों का एक नया सेट प्रस्तुत करता है। इन सभी की प्रासंगिकता इस बात पर निर्भर करेगी कि आप अपनी खोजों को कितनी बार प्रदर्शन करते हुए देखते हैं, और आपको उनकी कितनी प्रतिक्रिया की आवश्यकता है।


1

पूर्ण-पाठ अनुक्रमणिका की कई सीमाएँ हैं। आप वाइल्डकार्ड्स का उपयोग उन शब्दों पर कर सकते हैं जो इंडेक्स को पूरे "पार्ट्स" के रूप में देखते हैं, लेकिन फिर भी आप शब्द के अंतिम भाग के लिए विवश हैं। यही कारण है कि आप उपयोग कर सकते हैं CONTAINS(Name, '"Azimut*"')लेकिन नहींCONTAINS(Name, '"zimuth*"')

Microsoft दस्तावेज़ से :

जब उपसर्ग शब्द एक वाक्यांश है, तो वाक्यांश बनाने वाले प्रत्येक टोकन को एक अलग उपसर्ग शब्द माना जाता है। उपसर्ग शब्दों के साथ शुरुआत करने वाले सभी पंक्तियों को वापस कर दिया जाएगा। उदाहरण के लिए, उपसर्ग शब्द "लाइट ब्रेड *" में "लाइट ब्रेडेड," "लाइट ब्रेडेड," या "लाइट ब्रेड" के टेक्स्ट के साथ पंक्तियाँ मिलेंगी, लेकिन यह "लाइट टोस्टेड ब्रेड" नहीं लौटेगी।

ईमेल में डॉट्स, जैसा कि शीर्षक से संकेत मिलता है, मुख्य मुद्दा नहीं हैं। यह, उदाहरण के लिए, काम करता है:

SELECT * FROM NewCompanies 
WHERE CONTAINS((Email, Contacts1, Contacts2, Contacts3, Contacts4), 's.m.s@gmail.com') 

इस स्थिति में, सूचकांक पूरे ईमेल स्ट्रिंग को मान्य करता है, साथ ही साथ "gmail" और "gmail.com"। बस "एसएमएस" हालांकि मान्य नहीं है।

अंतिम उदाहरण समान है। फोन नंबर के हिस्सों को अनुक्रमित किया जाता है (उदाहरण के लिए 666-22-11 और 999-666-22-11), लेकिन हाइफ़न को हटाना एक स्ट्रिंग नहीं है जिसके बारे में सूचकांक को पता चल रहा है। अन्यथा, यह काम करता है:

SELECT * FROM NewCompanies 
WHERE CONTAINS((Phone, Contacts1, Contacts2, Contacts3, Contacts4), '"666-22-11*"')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.