2009-02-13 17 views
34

मान लीजिए मेरे पास दो कॉलम, कीवर्ड और सामग्री है। मेरे पास दोनों में एक पूर्ण टेक्स्ट इंडेक्स है। मैं सामग्री में foo के साथ पंक्ति में अधिक प्रासंगिकता रखने के लिए कीवर्ड में foo के साथ एक पंक्ति चाहता हूं। MySQL को सामग्री के मुकाबले कीवर्ड में मैचों को लोड करने के लिए मुझे क्या करने की आवश्यकता है?एक फ़ील्ड को दूसरे की तुलना में अधिक 'मूल्यवान' बनाने के लिए मैं MySQL पूर्ण टेक्स्ट खोज प्रासंगिकता का उपयोग कैसे कर सकता हूं?

मैं वाक्यविन्यास के खिलाफ "मैच" का उपयोग कर रहा हूं।

समाधान:

निम्नलिखित तरीके से इस काम करने के लिए सक्षम था:

SELECT *, 
CASE when Keywords like '%watermelon%' then 1 else 0 END as keywordmatch, 
CASE when Content like '%watermelon%' then 1 else 0 END as contentmatch, 
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data 
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
HAVING relevance > 0 
ORDER by keywordmatch desc, contentmatch desc, relevance desc 

उत्तर

19

वास्तव में, झंडे की एक जोड़ी बनाने के लिए एक मामला कथन का उपयोग एक बेहतर समाधान हो सकता है। मैंने यह भी धारणा की कि कीवर्ड और सामग्री दोनों में एक मैच उच्चतम रैंक है।

+0

ठीक है, मैं यह काम करने में सक्षम था। धन्यवाद! – Buzz

+3

जैसे कथन का उपयोग करना खोज चलाने के लिए एक शानदार तरीका नहीं है। सबसे पहले, जब तक आप तारों को विभाजित नहीं करते हैं, तो आप केवल सटीक क्रम में मेल खाते हैं। यानी 'LIKE'% t-shirt लाल% 'खोज' आपके डेटाबेस में 'लाल टी-शर्ट' से मेल नहीं खाएगा। दूसरा, आप अपनी क्वेरी निष्पादित करने के लिए उच्च समय के साथ समाप्त होते हैं, क्योंकि LIKE एक पूर्ण तालिका स्कैन करता है। – ChrisG

+1

@ChrisG 'LIKE' एक पूर्ण तालिका स्कैन करता है जब इसे' SELECT' – gontard

0

जहाँ तक मुझे पता है, यह MySQL की प्रतिलिपि प्राप्त खोज का समर्थन नहीं करता है, लेकिन आप प्रभाव को प्राप्त कर सकते हैं किसी भी तरह से उस शब्द को कीवर्ड फ़ील्ड में कई बार दोहराना। कीवर्ड "फू बार" रखने के बजाय, "foo bar foo bar foo bar" है, इस तरह दोनों कीवर्ड और कॉलम में फू और बार समान रूप से महत्वपूर्ण हैं, और चूंकि वे कई बार प्रकट होते हैं, वे mysql के लिए अधिक प्रासंगिक होते हैं।

हम इसे हमारी साइट पर उपयोग करते हैं और यह काम करता है।

-4

यदि मीट्रिक बस इतना है कि सभी कीवर्ड मिलान सभी सामग्री मिलानों की तुलना में अधिक "मूल्यवान" हैं तो आप केवल पंक्ति गणना के साथ एक संघ का उपयोग कर सकते हैं। इन लाइनों के साथ कुछ।

select * 
from (
    select row_number() over(order by blahblah) as row, t.* 
    from thetable t 
    where keyword match 

    union 

    select row_number() over(order by blahblah) + @@rowcount + 1 as row, t.* 
    from thetable t 
    where content match 
) 
order by row 

जहां प्रत्येक पंक्ति के लिए एक वास्तविक वजन लागू करना चाहते हैं कुछ भी है कि तुलना में अधिक जटिल, के लिए, मैं नहीं जानता कि कैसे मदद करने के लिए।

select 
... 
, case when keyword like '%' + @input + '%' then 1 else 0 end as keywordmatch 
, case when content like '%' + @input + '%' then 1 else 0 end as contentmatch 
-- or whatever check you use for the matching 
from 
    ... 
    and here the rest of your usual matching query 
    ... 
order by keywordmatch desc, contentmatch desc 

फिर, यह केवल है यदि सभी कीवर्ड मैचों रैंक सभी की तुलना में अधिक सामग्री से ही मेल खाता है:

+0

मैं इस की कोशिश की, और वाक्यविन्यास त्रुटियों के साथ समाप्त हो गया। मुझे नहीं लगता कि मुझे पता था कि ब्लाब्लाह स्पॉट द्वारा आदेश में क्या रखा जाए। सुझाव? – Buzz

+0

क्षमा करें, यह एक कॉपी और पेस्ट उदाहरण होने का मतलब नहीं था। ओवर क्लॉज में ऑर्डर वह ऑर्डर है जो आप पंक्ति संख्याओं को लागू करते हैं, इसलिए यह होना चाहिए कि आप सामान्य रूप से परिणामों को ऑर्डर करेंगे। – notnot

+0

अब जब मैं इसके बारे में सोचता हूं, तो यह उन रिकॉर्ड्स को डुप्लिकेट करेगा जो कीवर्ड और सामग्री दोनों से मेल खाते हैं। – notnot

-1

ठीक है, कि क्या पर निर्भर करता है कि वास्तव में आप मतलब के साथ है:

मैं खोजशब्दों में foo के साथ एक पंक्ति चाहते हैं सामग्री में foo के साथ एक पंक्ति की तुलना में अधिक प्रासंगिकता है।

आप का मतलब है कि कीवर्ड में foo के साथ एक पंक्ति सामग्री, तो मैं दो अलग-अलग प्रश्नों, कीवर्ड के लिए कोई और उसके बाद क्या करेंगे में foo साथ से पहले किसी भी पंक्ति आना चाहिए (संभवतः lazily हैं, केवल तभी अनुरोध किया जाता है जब सामग्री पर दूसरा।

0

मैंने कुछ साल पहले ऐसा किया था, लेकिन पूर्ण पाठ अनुक्रमणिका के बिना। मेरे पास कोड आसान नहीं है (पूर्व नियोक्ता), लेकिन मुझे तकनीक अच्छी तरह से याद है।

संक्षेप में, मैंने प्रत्येक कॉलम से "वजन" चुना है। उदाहरण के लिए:

select table.id, keyword_relevance + content_relevance as relevance from table 
    left join 
     (select id, 1 as keyword_relevance from table_name where keyword match) a 
    on table.id = a.id 
    left join 
     (select id, 0.75 as content_relevance from table_name where content match) b 
    on table.id = b.id 

यहां किसी भी घटिया एसक्यूएल forrgive कृपया, यह एक कुछ वर्षों के बाद से मैं किसी भी लिखने के लिए की जरूरत हो गया है, और मैं बंद मेरे सिर के ऊपर इस कर रहा हूँ ...

आशा इस मदद करता है!

J.Js

68

तीन पूरा टेक्स्ट अनुक्रमित

  • क) कीवर्ड कॉलम एक
  • ख) दोनों एक ही कीवर्ड और सामग्री पर सामग्री स्तंभ पर एक
  • ग) एक बनाएं कॉलम

फिर, आपकी क्वेरी:

SELECT id, keyword, content, 
    MATCH (keyword) AGAINST ('watermelon') AS rel1, 
    MATCH (content) AGAINST ('watermelon') AS rel2 
FROM table 
WHERE MATCH (keyword,content) AGAINST ('watermelon') 
ORDER BY (rel1*1.5)+(rel2) 

बिंदु यह है कि rel1 आपको keyword कॉलम में केवल अपनी क्वेरी की प्रासंगिकता देता है (क्योंकि आपने केवल उस कॉलम पर अनुक्रमणिका बनाई है)। rel2 वही करता है, लेकिन content कॉलम के लिए। अब आप इन दो प्रासंगिकता स्कोर को जोड़कर अपनी पसंद के भार को लागू कर सकते हैं।

हालांकि, अगर आप वास्तविक खोज के लिए इन किसी एक के इंडेक्स का उपयोग नहीं कर रहे हैं। इसके लिए, आप अपनी तीसरी अनुक्रमणिका का उपयोग करते हैं, जो दोनों कॉलम पर है।

(कीवर्ड, सामग्री) पर सूचकांक आपकी याद को नियंत्रित करता है। उर्फ, क्या लौटाया जाता है।

दो अलग-अलग अनुक्रमित (एक कीवर्ड पर केवल सामग्री पर एक ही) अपने प्रासंगिकता नियंत्रित करते हैं। और आप यहां अपना खुद का भार मानदंड लागू कर सकते हैं।

ध्यान दें कि आप किसी भी प्रकार की विभिन्न इंडेक्स का उपयोग कर सकते हैं (या, अन्य कारकों के आधार पर आप क्वेरी समय पर उपयोग किए गए इंडेक्स और वेटिंग्स को अलग-अलग कर सकते हैं ... केवल क्वेरी पर खोज करें यदि क्वेरी में स्टॉप शब्द है ... कमी कीवर्ड में वेटिंग पूर्वाग्रह यदि क्वेरी में 3 से अधिक शब्द हैं ... आदि)।

प्रत्येक सूचकांक डिस्क स्थान है, इसलिए अधिक अनुक्रमित है, और अधिक डिस्क का उपयोग करता है। और बदले में, mysql के लिए उच्च स्मृति पदचिह्न। साथ ही, प्रविष्टियों में अधिक समय लगेगा, क्योंकि आपके पास अपडेट करने के लिए अधिक अनुक्रमणिका हैं।

आपको बेंचमार्क प्रदर्शन अपनी स्थिति के लिए (और कुछ अपने परिणामों को बेंचमार्क करने के लिए mysql क्वेरी कैश बंद करने के लिए सावधान किया जा रहा विषम किया जाएगा) चाहिए। यह Google ग्रेड कुशल नहीं है, लेकिन यह बहुत आसान है और "बॉक्स से बाहर" है और यह निश्चित रूप से प्रश्नों में "जैसे" के उपयोग से बहुत बेहतर है।

मुझे लगता है कि यह वास्तव में अच्छी तरह से काम करता है।

+0

में 'FROM' खंड में उपयोग नहीं किया जाता है, ठीक से काम करता है और समझ में आता है। धन्यवाद! – Bretticus

+0

मुझे यह काम करने के लिए प्रतीत नहीं होता था (शायद क्योंकि मैंने तीसरी अनुक्रमणिका नहीं जोड़ा था), लेकिन जहां स्थिति को बदलना: rel1> 0 या rel2> 0 ने मेरी समस्या हल की है तो धन्यवाद। –

+1

@mintywalker को उच्चतम स्कोर प्राप्त करने के लिए ऑर्डर देना चाहिए (rel1 * 1.5) + (rel2) डीईएससी 'और इस प्रकार अधिक प्रासंगिक पहले? – PanPipes

0

बूलियन मोड में, MySQL ">" और "<" ऑपरेटर का समर्थन करता है ताकि पंक्ति में असाइन किए गए प्रासंगिकता मान में शब्द का योगदान बदल सके।

मुझे आश्चर्य है कि ऐसा कुछ काम करेगा या नहीं?

SELECT *, 
MATCH (Keywords) AGAINST ('>watermelon' IN BOOLEAN MODE) AS relStrong, 
MATCH (Title,Keywords,Content) AGAINST ('<watermelon' IN BOOLEAN MODE) AS relWeak 
FROM about_data 
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
ORDER by (relStrong+relWeak) desc 
0

मुझे कुछ समान चाहिए और ओपी के समाधान का उपयोग किया, लेकिन मैंने देखा कि पूर्ण टेक्स्ट आंशिक शब्दों से मेल नहीं खाता है। तो यदि शब्द के हिस्से के रूप में 'तरबूज' शब्द या सामग्री में है (जैसे watermelonsalesmanager) यह मेल नहीं करता है और WHERE MATCH के कारण परिणामों में शामिल नहीं है। तो मैं थोड़ा के आसपास मूर्ख बनाया है और इस के लिए ओपी की क्वेरी बदलाव:

SELECT *, 
CASE WHEN Keywords LIKE '%watermelon%' THEN 1 ELSE 0 END AS keywordmatch, 
CASE WHEN Content LIKE '%watermelon%' THEN 1 ELSE 0 END AS contentmatch, 
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data 
WHERE (Keywords LIKE '%watermelon%' OR 
    Title LIKE '%watermelon%' OR 
    MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE)) 
HAVING (keywordmatch > 0 OR contentmatch > 0 OR relevance > 0) 
ORDER BY keywordmatch DESC, contentmatch DESC, relevance DESC 

आशा इस मदद करता है।

1

सरल संस्करण केवल 2 की प्रतिलिपि प्राप्त अनुक्रमित (@mintywalker से लिया क्रेडिट) का उपयोग करते हुए:

SELECT id, 
    MATCH (`content_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance1, 
    MATCH (`title_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance2 
FROM search_table 
HAVING (relevance1 + relevance2) > 0 
ORDER BY (relevance1 * 1.5) + (relevance2) DESC 
LIMIT 0, 1000;