2013-02-25 17 views
5

Nel mio codice 3.6 stavo aggiungendo campo numerico al mio indice di come segue:come si fa a indice e searchnumbers in Lucene 4.1

public void addNumericField(IndexField field, Integer value) { 
     addField(field, NumericUtils.intToPrefixCoded(value)); 
    } 

tuttavia ora è necessario passare un argomento BytesRef, e la sua totalmente chiaro cosa che sono destinati a che fare con il valore successivo così invece ho cambiato in (work in progress)

public void addNumericField(IndexField field, Integer value) { 
     FieldType ft = new FieldType(); 
     ft.setStored(true); 
     ft.setIndexed(true); 
     ft.setNumericType(FieldType.NumericType.INT); 
     doc.add(new IntField(field.getName(), value, ft)); 
    } 

che sembrava più ordinato

in 3.6 ho anche aggiungere ignorare queryparser per farlo funzionare per le ricerche di intervalli numerici,

package org.musicbrainz.search.servlet; 

import org.apache.lucene.index.Term; 
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser; 
import org.apache.lucene.search.Query; 
import org.apache.lucene.search.TermQuery; 
import org.apache.lucene.search.TermRangeQuery; 
import org.apache.lucene.util.NumericUtils; 
import org.musicbrainz.search.LuceneVersion; 
import org.musicbrainz.search.index.LabelIndexField; 
import org.musicbrainz.search.servlet.mmd1.LabelType; 

public class LabelQueryParser extends MultiFieldQueryParser { 

    public LabelQueryParser(java.lang.String[] strings, org.apache.lucene.analysis.Analyzer analyzer) 
    { 
     super(LuceneVersion.LUCENE_VERSION, strings, analyzer); 
    } 

    protected Query newTermQuery(Term term) { 

     if(
       (term.field() == LabelIndexField.CODE.getName()) 
       ){ 
      try { 
       int number = Integer.parseInt(term.text()); 
       TermQuery tq = new TermQuery(new Term(term.field(), NumericUtils.intToPrefixCoded(number))); 
       return tq; 
      } 
      catch (NumberFormatException nfe) { 
       //If not provided numeric argument just leave as is, 
       //won't give matches 
       return super.newTermQuery(term); 
      } 
     } else { 
      return super.newTermQuery(term); 

     } 
    } 

    /** 
    * 
    * Convert Numeric Fields 
    * 
    * @param field 
    * @param part1 
    * @param part2 
    * @param inclusive 
    * @return 
    */ 
    @Override 
    public Query newRangeQuery(String field, 
           String part1, 
           String part2, 
           boolean inclusive) { 

     if (
       (field.equals(LabelIndexField.CODE.getName())) 
      ) 
     { 
      part1 = NumericUtils.intToPrefixCoded(Integer.parseInt(part1)); 
      part2 = NumericUtils.intToPrefixCoded(Integer.parseInt(part2)); 
     } 
     TermRangeQuery query = (TermRangeQuery) 
       super.newRangeQuery(field, part1, part2,inclusive); 
     return query; 
    } 

} 

Allora presi tutto questo capire Non ho più bisogno, ma purtroppo nessuna query su questo IntField stanno lavorando.

Leggere ulteriormente sembra che gli Intfields vengano utilizzati solo per le query di intervallo, quindi non so come si intende fare solo le query di corrispondenza e se NumericRangeQuery è compatibile con il classico parser di query che sto utilizzando.

Così ho poi andato di nuovo a cercare di aggiungere i miei valori numerici come stringa codificata

public void addNumericField(IndexField field, Integer value) { 

    FieldType fieldType = new FieldType(); 
    fieldType.setStored(true); 
    fieldType.setIndexed(true); 
    BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
    NumericUtils.intToPrefixCoded(value, 0, bytes); 
    doc.add(new Field(field.getName(),bytes, fieldType)); 
} 

Ma in fase di esecuzione Ora sto ottenendo l'errore!

java.lang.IllegalArgumentException: Fields with BytesRef values cannot be indexed 

ma ho bisogno di campo indice, quindi per favore come si può indice i campi numerici come faccio io in 3.6 modo che io possa cercare loro.

risposta

1

Basta usare il campo appropriato. Per esempio IntField, LongField, ecc

Si veda ad esempio http://lucene.apache.org/core/4_1_0/core/org/apache/lucene/document/IntField.html

Per l'interrogazione di questi campi, vedere Lucene LongField exact search with Query

+0

Ma se si utilizza IntField, come estendere QueryParser per cercare tali campi? –

+1

Restituisce il valore NumericRangeQuery appropriato nell'analisi del valore su un numero intero. Quindi, invece di restituire un TermQuery, restituire un oggetto NumericRangeQuery nel metodo newTermQuery, se necessario. – RobAu

0

Quindi ho ottenuto questo funzionamento, anche se questo è il modo migliore per fare cose che non so.

  1. Aggiunta numero all'indice come stringa

    FieldType fieldType = new FieldType(); 
    fieldType.setStored(true); 
    fieldType.setIndexed(true); 
    BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
    NumericUtils.intToPrefixCoded(value, 0, bytes); 
    doc.add(new Field(field.getName(),bytes.utf8ToString(), fieldType)); 
    
  2. QueryParser, deve controllare fieldname usando uguali(), precedentemente potrebbe sporgere uso ==

    protected Query newTermQuery(Term term) 
    { 
    
        if (term.field().equals(LabelIndexField.CODE.getName())) 
        { 
         try 
         { 
    
          int number = Integer.parseInt(term.text()); 
          BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
          NumericUtils.intToPrefixCoded(number, 0, bytes); 
          TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString())); 
          return tq; 
         } 
         catch (NumberFormatException nfe) 
         { 
          //If not provided numeric argument just leave as is, won't give matches 
          return super.newTermQuery(term); 
         } 
        } 
        else 
        { 
         return super.newTermQuery(term); 
    
        } 
    } 
    
  3. Anche la firma newRangeQuery() è cambiato, c'è un ulteriore parametro endInclusive

    public Query newRangeQuery(String field, 
              String part1, 
              String part2, 
              boolean startInclusive, 
              boolean endInclusive) 
    { 
        if (
          (field.equals(LabelIndexField.CODE.getName())) 
          ) 
        { 
         BytesRef bytes1 = new BytesRef(NumericUtils.BUF_SIZE_INT); 
         BytesRef bytes2 = new BytesRef(NumericUtils.BUF_SIZE_INT); 
         NumericUtils.intToPrefixCoded(Integer.parseInt(part1), 0, bytes1); 
         NumericUtils.intToPrefixCoded(Integer.parseInt(part2), 0, bytes2); 
         part1 = bytes1.utf8ToString(); 
         part2 = bytes2.utf8ToString(); 
        } 
        TermRangeQuery query = (TermRangeQuery) 
          super.newRangeQuery(field, part1, part2, startInclusive, endInclusive); 
        return query; 
    
    } 
    
  4. È possibile ottenere il valore intgeral originale fuori dell'indice come segue

    NumericUtils.prefixCodedToInt(new BytesRef(code)) 
    
2

Solo un testa a testa, su come farlo utilizzando Lucene 4.7:

Quando l'indicizzazione Io faccio solo come folows:

document.add(new IntField("int_field", int_value, Field.Store.YES)); 

E per la ricerca:

public class MyQueryParser extends QueryParser { 

public MyQueryParser(Version matchVersion, String field, Analyzer anlayzer) { 
    super(matchVersion, field, anlayzer); 
} 

@Override 
protected Query getRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) throws ParseException { 
    if ("int_field".equals(field)) { 
     return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2), startInclusive, endInclusive); 
    } else { 
     return super.getRangeQuery(field, part1, part2, startInclusive, endInclusive); 
    } 
} 

@Override 
protected Query newTermQuery(Term term) 
{ 
    if ("int_field".equals(term.field())) { 
     try { 
      int number = Integer.parseInt(term.text()); 
      BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
      NumericUtils.intToPrefixCoded(number, 0, bytes); 
      TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString())); 
      return tq; 
     } catch (NumberFormatException nfe) { 
      //If not provided numeric argument just leave as is, won't give matches 
      return super.newTermQuery(term); 
     } 
    } else { 
     return super.newTermQuery(term); 
    } 
} 

}

Facendo in questo modo, querys come

int_field: 1 
int_field: [1 TO 5] 

funziona come previsto.