2012-12-28 6 views
13

Ich versuche, einen Index von Dokumenten zu implementieren (ähnlich wie DB-Zeilen), wobei eines der Felder eine Ganzzahl ist. Ich füge sie zu indizieren wie:Wie ein Int-Feld in Lucene 4 zu suchen?

Document doc = new Document(); 
doc.add(new StringField("ticket_number", rs.getString("ticket_number"), 
     Field.Store.YES)); 
doc.add(new IntField("ticket_id", rs.getInt("ticket_id"), 
     Field.Store.YES)); 
doc.add(new StringField("id_s", rs.getString("ticket_id"), 
     Field.Store.YES)); 
w.addDocument(doc); 

Es scheint, dass ich nicht das ticket_id Feld überhaupt abfragen können, während id_s funktioniert gut.

Eines der Dokumente ist (habe ich Leerzeichen zur besseren Lesbarkeit):

Document< 
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<ticket_number:230114W> 
    stored<ticket_id:152> 
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<id_s:152>> 

So ist mein int Feld gespeichert, aber nicht indiziert. Diese Abfrage funktioniert wie erwartet: id_s:152, während dieser nie zurückgibt: ticket_id:152.

Was mache ich falsch? Wie kann ich ein solches Feld zum Index hinzufügen und durchsuchbar machen?

Antwort

7

Numerische Felder können mit einem NumericRangeQuery abgefragt werden. Um eine exakte Übereinstimmung zu erzielen, setzen Sie einfach max und min auf die gleichen Werte.

Ihre Ausgabe, die angibt, dass das Feld nicht indiziert ist, könnte auf die Unterschiede in der Indexierung eines numerischen Werts im Vergleich zu einem Textwert zurückzuführen sein. Wenn man bedenkt, dass das Feld in die numerische Darstellung von Lucene transformiert wird, wird der Literalwert 152 tatsächlich nicht indiziert.

Auf einen Blick ist es jedoch möglich, dass Ihre Handhabung von id_s die bessere Alternative ist. IDs werden normalerweise nicht als numerische Werte behandelt, sondern nur als einfache Bezeichner, die mit Ziffern dargestellt werden. Wenn Sie keine numerische Sortierung oder Bereichsabfrage für das Feld benötigen, ist die Indexierung als StringField sicherlich sinnvoller.

18

arbeitet Below für mich:

RAMDirectory idx = new RAMDirectory(); 
    IndexWriter writer = new IndexWriter(
      idx, 
      new IndexWriterConfig(Version.LUCENE_40, new ClassicAnalyzer(Version.LUCENE_40)) 
    ); 
    Document document = new Document(); 
    document.add(new StringField("ticket_number", "t123", Field.Store.YES)); 
    document.add(new IntField("ticket_id", 234, Field.Store.YES)); 
    document.add(new StringField("id_s", "234", Field.Store.YES)); 
    writer.addDocument(document); 
    writer.commit(); 

    IndexReader reader = DirectoryReader.open(idx); 
    IndexSearcher searcher = new IndexSearcher(reader); 

    Query q1 = new TermQuery(new Term("id_s", "234")); 
    TopDocs td1 = searcher.search(q1, 1); 
    System.out.println(td1.totalHits); // prints "1" 

    Query q2 = NumericRangeQuery.newIntRange("ticket_id", 1, 234, 234, true, true); 
    TopDocs td2 = searcher.search(q2, 1); 
    System.out.println(td2.totalHits); // prints "1" 

Wie femtoRgon wies darauf hin, für numerische Werte (longs, Datteln, Schwimmern, etc.) Sie NumericRangeQuery und Präzision angeben müssen. Ansonsten hat Lucene keine Ahnung, wie Sie Ähnlichkeit definieren möchten.

+0

Danke Mann, dieser hat mir sehr geholfen. – SoluableNonagon

+0

Gibt '234' das gleiche Stück Daten an, wenn nicht, halte ich es nicht für richtig, es zweimal im Index zu speichern, einmal als String und einmal als Int. –

+0

'234' wird mit verschiedenen Feldern gespeichert (' ticket_id' und 'id_s'). Ich sehe damit nichts falsch. Konzeptionell mag das falsch sein, aber der Zweck dieses Beispiels ist nur zu beweisen, dass beide Techniken möglich sind. – mindas

4

Eine andere Antwort kommt aus diesem Thread (dritte Antwort): Lucene 4.0 IndexWriter updateDocument for Numeric Term

Grundsätzlich Sie einen Begriff mit int Wert wie folgt erstellen:

String field = "myfield"; 
int value = 4711; 
BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
NumericUtils.intToPrefixCoded(value, 0, bytes); 
Term term = new Term(field, bytes); 

Dann Sie diesen Begriff für die Suche verwenden können, oder Löschen/Aktualisieren Ihres Indexes. In einem ersten Test hat das für mich funktioniert. Ich kann nicht sagen, ob dies der "richtige" Weg ist, Dinge zu tun. Ich habe den NumericRangeFilter zuvor zum Filtern von IntFields verwendet, aber jetzt neige ich dazu, diesen Ansatz zu verwenden und stattdessen reguläre TermsFilter oder TermQueries zu verwenden.