2012-12-28 5 views
13

Sto provando ad implementare un indice di documenti (rougly corrispondente alle righe del DB), dove uno dei campi è un numero intero. Li sto aggiungendo all'indice come:Come cercare un campo int in Lucene 4?

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); 

Sembra che io non posso interrogare il campo ticket_id a tutti, mentre id_s funziona bene.

Uno dei documenti è (ho aggiunto spazio bianco per migliorare la leggibilità):

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>> 

Quindi il mio campo int è memorizzato, ma non indicizzati. Questa query funziona come previsto: id_s:152, mentre questo non restituisce mai nulla: ticket_id:152.

Cosa sto sbagliando? Come posso aggiungere un campo di questo tipo all'indice e renderlo ricercabile?

risposta

7

I campi numerici possono essere interrogati con un NumericRangeQuery. Per una corrispondenza esatta, è sufficiente impostare il valore massimo e minimo su valori uguali.

L'output che indica che il campo non è indicizzato potrebbe essere dovuto alle differenze nel modo in cui un valore numerico viene indicizzato, rispetto a un valore di testo. Considerando che il campo viene trasformato nella rappresentazione numerica di Lucene, il valore letterale 152 non verrà effettivamente indicizzato

In breve, tuttavia, è possibile che la gestione degli id_s sia l'alternativa migliore. Gli ID non vengono solitamente gestiti come valori numerici, ma piuttosto come semplici identificatori che sono rappresentati con cifre. Se non hai bisogno di ordinamento numerico o intervallo di query sul campo, l'indicizzazione come StringField ha sicuramente più senso.

18

seguito funziona per me:

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" 

Come femtoRgon sottolineato, per i valori numerici (long, date, galleggianti, ecc) hai bisogno di NumericRangeQuery e specificare la precisione. Altrimenti Lucene non ha idea di come si voglia definire la somiglianza.

+0

Grazie amico, questo mi ha aiutato molto. – SoluableNonagon

+0

Does '234' indica lo stesso pezzo di dati, in tal caso non penso che sia giusto memorizzarlo nell'indice due volte, una volta come una stringa e una volta come un int. –

+0

'234' è memorizzato con campi diversi (' ticket_id' e 'id_s'). Non vedo niente di sbagliato in questo. Concettualmente questo potrebbe essere sbagliato, ma lo scopo di questo esempio è solo quello di dimostrare che entrambe le tecniche sono possibili. – mindas

4

Un'altra risposta viene da questa discussione (terza risposta): Lucene 4.0 IndexWriter updateDocument for Numeric Term

In sostanza, si crea un termine con il vostro valore int in questo modo:

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); 

quindi è possibile utilizzare questo termine per la ricerca, o cancellare/aggiornare il tuo indice In una prima prova, questo ha funzionato bene per me. Non posso dire se questo è il modo "giusto" di fare le cose comunque. Ho usato NumericRangeFilter in precedenza per filtrare IntFields, ma ora sono incline a utilizzare questo approccio e utilizzare invece TermsFilter normale o TermQueries.