2011-09-30 4 views
7

सोलर (3.3) में सटीक वाक्यांश क्वेरी, क्या EdgeNGramFilterFactory के माध्यम से एक फ़ील्ड लेटर-बाय-लेटर खोजने योग्य है और वाक्यांश क्वेरी के प्रति संवेदनशील भी है?सोलर: एक EdgeNGramFilterFactory

उदाहरण से, मैं एक क्षेत्र है कि, अगर "Contrat informatique" युक्त, मिल जाएगा के लिए देख रहा हूँ, तो उपयोगकर्ता प्रकार:

  • Contrat
  • informatique
  • contr
  • सूचना
  • "Contrat informatique"
  • "Contrat जानकारी"

वर्तमान में, मैं कुछ इस तरह बनाया:

<fieldtype name="terms" class="solr.TextField"> 
    <analyzer type="index"> 
     <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> 
     <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> 
     <tokenizer class="solr.LowerCaseTokenizerFactory"/> 
     <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/> 
    </analyzer> 
    <analyzer type="query"> 
     <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/> 
     <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> 
     <tokenizer class="solr.LowerCaseTokenizerFactory"/> 
    </analyzer> 
</fieldtype> 

... लेकिन यह वाक्यांश प्रश्नों पर असफल रहा।

जब मैं Solr व्यवस्थापक में स्कीमा विश्लेषक में लग रहे हैं, मुझे लगता है कि "Contrat informatique" निम्न टोकन उत्पन्न:

[...] contr contra contrat in inf info infor inform [...] 

तो क्वेरी (लगातार टोकन) "में Contrat" ​​के साथ काम करता है, लेकिन नहीं "contrat inf" (क्योंकि यह दो टोकन अलग हैं)।

मुझे यकीन है कि किसी भी तरह का स्टेमिंग वाक्यांश प्रश्नों के साथ काम कर सकता है, लेकिन मुझे EdgeNGramFilterFactory से पहले उपयोग करने के लिए फ़िल्टर का सही टोकननाइज़र नहीं मिल रहा है।

उत्तर

2

अफसोस जैसा कि मैंने एक PositionFilter सही तरह जयेंद्र पाटिल सुझाव दिया उपयोग करने के लिए प्रबंधन नहीं कर सके (PositionFilter किसी भी प्रश्न एक या बूलियन क्वेरी बनाता है), मैं प्रयोग किया जाता है एक अलग दृष्टिकोण।

अभी भी EdgeNGramFilter के साथ, मैंने यह तथ्य जोड़ा कि उपयोगकर्ता द्वारा टाइप किए गए प्रत्येक कीवर्ड अनिवार्य है, और सभी वाक्यांशों को अक्षम कर दिया गया है।

तो यदि उपयोगकर्ता "cont info" के लिए पूछता है, तो यह +cont +info में बदल जाता है। यह थोड़ा और अनुमोदित है कि एक सच्चा वाक्यांश होगा, लेकिन यह वही करने में कामयाब रहा जो मैं चाहता हूं (और दोनों से केवल एक शब्द के साथ परिणाम नहीं लौटाता है)।

इस कामकाज के खिलाफ एकमात्र कांग्रेस यह है कि परिणामों में शब्दों को क्रमबद्ध किया जा सकता है (इसलिए "informatique contrat" ​​वाला एक दस्तावेज़ भी मिलेगा), लेकिन यह एक बड़ा सौदा नहीं है।

+0

हाय, जेवियर। क्या आप कृपया बता सकते हैं कि आपने "cont info" को + cont + info में कैसे बदल दिया है, इसके लिए बॉक्स उपयोग कक्षा में से कोई भी जानकारी है? या यह सिर्फ दोहरे उद्धरणों की पहचान करता है और मैन्युअल रूप से बदल जाता है? मैं इसे हल करने की कोशिश कर रहा हूं: http: // stackoverflow।कॉम/प्रश्न/37033381/सोलर-सर्च-फील्ड-बेस्ट प्रैक्टिस – wattale

+0

यह मैन्युअल ऑपरेशन था, जो डबल कोटेशन की तलाश में था और प्लस साइन जोड़ रहा था। मुझे ऐसा कुछ भी नहीं मिला जो मेरे लिए इसे स्वचालित कर सके: -/ –

+0

उत्तर xavier के लिए धन्यवाद, मेरे लिए इतनी सारी सामग्री को क्रॉल करने के बाद भी बॉक्स समाधान से बाहर नहीं मिला। मैंने सोचा कि मैं इसे मैन्युअल रूप से कर कर पहिया को फिर से शुरू कर रहा हूं। लेकिन मुझे लगता है कि इसे मैन्युअल रूप से करने का एकमात्र विकल्प उपलब्ध है: | – wattale

1

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

तो तुम संकेत करके देख सकते हैं: -

<analyzer type="index"> 
    <tokenizer class="solr.WhitespaceTokenizerFactory" /> 
    <charFilter class="solr.MappingCharFilterFactory" 
      mapping="mapping-ISOLatin1Accent.txt" /> 
    <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" 
      generateNumberParts="1" catenateWords="1" catenateNumbers="1" 
      catenateAll="0" splitOnCaseChange="1"/> 
    <filter class="solr.LowerCaseFilterFactory" /> 
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" 
      maxGramSize="15" side="front"/> 
    <filter class="solr.PositionFilterFactory" /> 
</analyzer> 
+0

विचार साफ है, लेकिन यह वैसे भी काम नहीं कर रहा है: -/अगर मुझे व्यवस्थापक विश्लेषण उपकरण के माध्यम से मिलते हैं, तो असली क्वेरी कुछ भी नहीं लौटाती है (शायद क्योंकि विश्लेषण टूल में, जिस तरह से यह टोकन को हाइलाइट करता है, वाक्यांशों से परेशान नहीं होता)। इसके अलावा, [PositionFilter] (http://tinyurl.com/solr-positionfilter) बनाता क्वेरी _boolean_ रूप विकि पर कहा, तो "Contrat informatique" या फिर "+ Contrat + informatique" "Contrat" ​​लेकिन यह भी बिना के साथ दस्तावेजों रिटर्न डिफ़ॉल्ट सूचना के रूप में "informatique" एक OR है। एक संभावित विकल्प + contrat + informatique में क्वेरी को बदलने के लिए होगा, मुझे लगता है। –

4

सटीक वाक्यांश खोज डिफ़ॉल्ट रूप से क्वेरी ढिलाई पैरामीटर की वजह से काम नहीं करता है = 0। वाक्यांश "हैलो वर्ल्ड" के लिए खोज रहे हैं, यह अनुक्रमिक पदों के साथ शब्दों की खोज करता है। मेरी इच्छा है कि EdgeNGramFilter में आउटपुट पोजिशनिंग को नियंत्रित करने के लिए पैरामीटर था, यह पुराने question जैसा दिखता है।

कुछ बहुत ही उच्च मूल्य (ngrams के बीच अधिकतम दूरी से अधिक) के लिए qs पैरामीटर की स्थापना करके आप वाक्यांशों वापस मिल सकता है। यह आंशिक रूप से वाक्यांशों को अनुमति देने में समस्या हल करता है, लेकिन सटीक नहीं है, क्रमिक क्रम भी पाए जाएंगे। तो "Contrat informatique" की तरह पाठ से मेल खाएगा कि खोज "... अनुबंध को छोड़ दिया। Informatique ..."

enter image description here

सटीक वाक्यांश क्वेरी मैं अंत separate fields for ngrams उपयोग करने के लिए समर्थन करने के लिए।

कदम आवश्यक:

सूचकांक नियमित मूल्यों और ग्राम अलग क्षेत्र प्रकार निर्धारित करें:

<fieldType name="text" class="solr.TextField" omitNorms="false"> 
    <analyzer> 
    <tokenizer class="solr.StandardTokenizerFactory"/> 
    <filter class="solr.LowerCaseFilterFactory"/> 
    </analyzer> 
</fieldType> 

<fieldType name="ngrams" class="solr.TextField" omitNorms="false"> 
    <analyzer type="index"> 
    <tokenizer class="solr.StandardTokenizerFactory"/> 
    <filter class="solr.LowerCaseFilterFactory"/> 
    <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/> 
    </analyzer> 
    <analyzer type="query"> 
    <tokenizer class="solr.StandardTokenizerFactory"/> 
    <filter class="solr.LowerCaseFilterFactory"/> 
    </analyzer> 
</fieldType> 

copy fields को Solr में बताएं जब अनुक्रमण:

आप प्रत्येक के लिए अलग ngrams प्रतिबिंब परिभाषित कर सकते हैं क्षेत्र:

<field name="contact_ngrams" type="ngrams" indexed="true" stored="false"/> 
<field name="product_ngrams" type="ngrams" indexed="true" stored="false"/> 
<copyField source="contact_text" dest="contact_ngrams"/> 
<copyField source="product_text" dest="product_ngrams"/> 

या आप एक क्षेत्र में सभी ngrams रख सकते हैं:

<field name="heap_ngrams" type="ngrams" indexed="true" stored="false"/> 
<copyField source="*_text" dest="heap_ngrams"/> 

ध्यान दें कि आप इस मामले में बूस्टर अलग करने में सक्षम नहीं हो जाएगा।

और अंत में क्वेरी में खेतों और बूस्टर ngrams निर्दिष्ट करने के लिए है। एक तरीका है अपने आवेदन को कॉन्फ़िगर करना। एक और तरीका है निर्दिष्ट करने के लिए है "संलग्न कर देता है" solrconfig.xml

<lst name="appends"> 
    <str name="qf">heap_ngrams</str> 
    </lst> 
1

मैं EdgeNGramFilter करने के लिए एक ठीक कर दिया है ताकि एक टोकन के भीतर पदों अब और वृद्धि नहीं कर रहे हैं में पैरामीटर:

public class CustomEdgeNGramTokenFilterFactory extends TokenFilterFactory { 
    private int maxGramSize = 0; 

    private int minGramSize = 0; 

    @Override 
    public void init(Map<String, String> args) { 
     super.init(args); 
     String maxArg = args.get("maxGramSize"); 
     maxGramSize = (maxArg != null ? Integer.parseInt(maxArg) 
       : EdgeNGramTokenFilter.DEFAULT_MAX_GRAM_SIZE); 

     String minArg = args.get("minGramSize"); 
     minGramSize = (minArg != null ? Integer.parseInt(minArg) 
       : EdgeNGramTokenFilter.DEFAULT_MIN_GRAM_SIZE); 

    } 

    @Override 
    public CustomEdgeNGramTokenFilter create(TokenStream input) { 
     return new CustomEdgeNGramTokenFilter(input, minGramSize, maxGramSize); 
    } 
} 
public class CustomEdgeNGramTokenFilter extends TokenFilter { 
    private final int minGram; 
    private final int maxGram; 
    private char[] curTermBuffer; 
    private int curTermLength; 
    private int curGramSize; 

    private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); 
    private final OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); 
    private final PositionIncrementAttribute positionIncrementAttribute = addAttribute(PositionIncrementAttribute.class); 

    /** 
    * Creates EdgeNGramTokenFilter that can generate n-grams in the sizes of the given range 
    * 
    * @param input {@link org.apache.lucene.analysis.TokenStream} holding the input to be tokenized 
    * @param minGram the smallest n-gram to generate 
    * @param maxGram the largest n-gram to generate 
    */ 
    public CustomEdgeNGramTokenFilter(TokenStream input, int minGram, int maxGram) { 
     super(input); 

     if (minGram < 1) { 
      throw new IllegalArgumentException("minGram must be greater than zero"); 
     } 

     if (minGram > maxGram) { 
      throw new IllegalArgumentException("minGram must not be greater than maxGram"); 
     } 

     this.minGram = minGram; 
     this.maxGram = maxGram; 
    } 

@Override 
public final boolean incrementToken() throws IOException { 
    while (true) { 
     int positionIncrement = 0; 
     if (curTermBuffer == null) { 
      if (!input.incrementToken()) { 
       return false; 
      } else { 
       positionIncrement = positionIncrementAttribute.getPositionIncrement(); 
       curTermBuffer = termAtt.buffer().clone(); 
       curTermLength = termAtt.length(); 
       curGramSize = minGram; 
      } 
     } 
     if (curGramSize <= maxGram) { 
      if (!(curGramSize > curTermLength   // if the remaining input is too short, we can't generate any n-grams 
        || curGramSize > maxGram)) {  // if we have hit the end of our n-gram size range, quit 
       // grab gramSize chars from front 
       int start = 0; 
       int end = start + curGramSize; 
       offsetAtt.setOffset(start, end); 
       positionIncrementAttribute.setPositionIncrement(positionIncrement); 
       termAtt.copyBuffer(curTermBuffer, start, curGramSize); 
       curGramSize++; 

       return true; 
      } 
     } 
     curTermBuffer = null; 
    } 
} 

    @Override 
    public void reset() throws IOException { 
     super.reset(); 
     curTermBuffer = null; 
    } 
}