2008-09-30 15 views
18

मैं उत्पादों की सूची पर खोज लागू करने के लिए लुसीन जावा 2.3.2 का उपयोग करने की कोशिश कर रहा हूं। किसी उत्पाद के लिए नियमित फ़ील्ड के अलावा, 'श्रेणी' नामक फ़ील्ड है। एक उत्पाद कई श्रेणियों में गिर सकता है। वर्तमान में, मैं प्रति श्रेणी परिणामों की संख्या प्राप्त करने के लिए प्रत्येक श्रेणी के साथ एक ही खोज शब्द खोजने के लिए FilteredQuery का उपयोग करता हूं।श्रेणियों में परिणाम गणना करने के लिए लुसेन का उपयोग

परिणामस्वरूप परिणाम प्रदर्शित करने के लिए प्रति प्रश्न 20-30 आंतरिक खोज कॉल में परिणाम मिलता है। यह खोज को काफी धीमा कर रहा है। लुसीन का उपयोग कर एक ही परिणाम प्राप्त करने का एक तेज तरीका है?

उत्तर

2

आप TermDocs iterator का उपयोग कर श्रेणियों से मेल खाने वाले सभी दस्तावेजों को देखने पर विचार करना चाहेंगे।

यह उदाहरण कोड प्रत्येक "श्रेणी" अवधि के माध्यम से जाता है, और उसके बाद उस शब्द से मेल खाने वाले दस्तावेज़ों की संख्या की गणना करता है।

public static void countDocumentsInCategories(IndexReader reader) throws IOException { 
    TermEnum terms = null; 
    TermDocs td = null; 


    try { 
     terms = reader.terms(new Term("Category", "")); 
     td = reader.termDocs(); 
     do { 
      Term currentTerm = terms.term(); 

      if (!currentTerm.field().equals("Category")) { 
       break; 
      } 

      int numDocs = 0; 
      td.seek(terms); 
      while (td.next()) { 
       numDocs++; 
      } 

      System.out.println(currentTerm.field() + " : " + currentTerm.text() + " --> " + numDocs); 
     } while (terms.next()); 
    } finally { 
     if (td != null) td.close(); 
     if (terms != null) terms.close(); 
    } 
} 

यह कोड बड़ी अनुक्रमणिका के लिए भी तेजी से चलना चाहिए। (!):

यहाँ कुछ कोड है कि विधि का परीक्षण करती है

public static void main(String[] args) throws Exception { 
    RAMDirectory store = new RAMDirectory(); 

    IndexWriter w = new IndexWriter(store, new StandardAnalyzer()); 
    addDocument(w, 1, "Apple", "fruit", "computer"); 
    addDocument(w, 2, "Orange", "fruit", "colour"); 
    addDocument(w, 3, "Dell", "computer"); 
    addDocument(w, 4, "Cumquat", "fruit"); 
    w.close(); 

    IndexReader r = IndexReader.open(store); 
    countDocumentsInCategories(r); 
    r.close(); 
} 

private static void addDocument(IndexWriter w, int id, String name, String... categories) throws IOException { 
    Document d = new Document(); 
    d.add(new Field("ID", String.valueOf(id), Field.Store.YES, Field.Index.UN_TOKENIZED)); 
    d.add(new Field("Name", name, Field.Store.NO, Field.Index.UN_TOKENIZED)); 

    for (String category : categories) { 
     d.add(new Field("Category", category, Field.Store.NO, Field.Index.UN_TOKENIZED)); 
    } 

    w.addDocument(d); 
} 
+0

यह केवल श्रेणी फ़ील्ड में प्रत्येक शब्द द्वारा टैग किए गए दस्तावेज़ों की गणना करता है, जो आप terms.docFreq() के साथ बहुत तेज़ी से कर सकते हैं। क्या गुम है उपयोगकर्ता के खोज मानदंडों से हिट के साथ छेड़छाड़ है। – erickson

8

मैं टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है, लेकिन मैट बटेर के जवाब में मैं यकीन है कि आप इस बदल सकते कर रहा हूँ:

int numDocs = 0; 
td.seek(terms); 
while (td.next()) { 
    numDocs++; 
} 
इस के साथ

:

int numDocs = terms.docFreq() 

और फिर टीडी चर का पूरी तरह छुटकारा पाने के। यह इसे और भी तेज बनाना चाहिए।

+0

आप वहां कभी भी नहीं होंगे (टिप्पणी) – mattlant

+0

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

0

तो मुझे देखने दो कि क्या मैं सही तरीके से प्रश्न समझता हूं: उपयोगकर्ता से एक प्रश्न को देखते हुए, आप यह दिखाना चाहते हैं कि प्रत्येक श्रेणी में क्वेरी के लिए कितने मैच हैं। सही बात?

इस तरह से सोचें: आपकी क्वेरी वास्तव में originalQuery AND (category1 OR category2 or ...) है, साथ ही साथ कुल मिलाकर आप प्रत्येक श्रेणी के लिए एक संख्या प्राप्त करना चाहते हैं। दुर्भाग्यवश लुसीन में हिट इकट्ठा करने के लिए इंटरफ़ेस बहुत संकीर्ण है, केवल आपको एक क्वेरी के लिए एक समग्र स्कोर दे रहा है। लेकिन आप एक कस्टम स्कोरर/कलेक्टर को लागू कर सकते हैं।

org.apache.lucene.search.DisjunctionSumScorer के स्रोत पर नज़र डालें। आप उसमें से कुछ को कस्टम स्कोरर लिखने के लिए कॉपी कर सकते हैं जो आपकी मुख्य खोज चालू होने पर श्रेणी मिलान के माध्यम से पुनरावृत्त होता है। और आप प्रत्येक श्रेणी में मैचों का ट्रैक रखने के लिए Map<String,Long> रख सकते हैं।

9

यहाँ मैं क्या किया है, हालांकि यह स्मृति पर थोड़ा भारी है:

क्या आप की जरूरत पहले से BitSet रों, प्रत्येक श्रेणी के लिए एक का एक समूह बनाने के लिए, एक में सभी दस्तावेजों की दस्तावेज़ ID युक्त वर्ग। अब, खोज समय पर आप HitCollector का उपयोग करें और बिट्स के खिलाफ दस्तावेज़ आईडी देखें।

यहाँ सा सेट बनाने के कोड है:

public BitSet[] getBitSets(IndexSearcher indexSearcher, 
          Category[] categories) { 
    BitSet[] bitSets = new BitSet[categories.length]; 
    for(int i=0; i<categories.length; i++) 
    { 
     Query query = categories[i].getQuery(); 
     final BitSet bitset = new BitSet() 
     indexSearcher.search(query, new HitCollector() { 
      public void collect(int doc, float score) { 
       bitSet.set(doc); 
      } 
     }); 
     bitSets[i] = bitSet; 
    } 
    return bitSets; 
} 

यह सिर्फ एक तरीका यह है है। यदि आपकी श्रेणियां काफी सरल हैं, तो आप शायद पूरी तरह से खोज करने के बजाय TermDocs का उपयोग कर सकते हैं, लेकिन यह तब भी चलाना चाहिए जब आप इंडेक्स को वैसे भी लोड करते हैं।

अब, जब यह खोज की श्रेणियों गिनती करने के लिए समय आ गया है जब आप यह कर परिणाम:

public int[] getCategroryCount(IndexSearcher indexSearcher, 
           Query query, 
           final BitSet[] bitSets) { 
    final int[] count = new int[bitSets.length]; 
    indexSearcher.search(query, new HitCollector() { 
     public void collect(int doc, float score) { 
      for(int i=0; i<bitSets.length; i++) { 
       if(bitSets[i].get(doc)) count[i]++; 
      } 
     } 
    }); 
    return count; 
} 

क्या आप के साथ अंत खोज परिणामों के भीतर हर वर्ग की गिनती युक्त एक सरणी है। यदि आपको खोज परिणामों की भी आवश्यकता है, तो आपको अपने हिट कलेक्टर (yo dawg ...) में एक टॉपडोकॉलिलेटर जोड़ना चाहिए। या, आप फिर से खोज चला सकते हैं। 2 खोज 30 से बेहतर हैं।

+1

getCategoryCount भाग के लिए अन्य कार्यान्वयन: आप वास्तव में अपनी खोज से एक बिटसेट प्राप्त कर सकते हैं (एक कलेक्टर का उपयोग करके) और फिर उस श्रेणी को बिटरसेट करें जिसमें आप रुचि रखते हैं बिटस्सेट जिसमें आप रुचि रखते हैं। प्रत्येक दस्तावेज़ की जांच करने से छेड़छाड़ तेज होनी चाहिए, और आप भी अंतर कर सकते हैं परिणाम बिट्ससेट के साथ छेड़छाड़ करने से पहले कई श्रेणियां। –

2

सचिन, मुझे विश्वास है कि आप faceted search चाहते हैं। यह ल्यूसीन के साथ बॉक्स से बाहर नहीं आता है। मेरा सुझाव है कि आप SOLR का उपयोग करने का प्रयास करें, जिसमें faceting एक प्रमुख और सुविधाजनक सुविधा के रूप में है।

संबंधित मुद्दे