2013-02-25 10 views
5

W moim kodu 3,6 byłem dodając pole numeryczne do mojego indeksu w następujący sposób:jak ty indeksu i searchnumbers w Lucene 4.1

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

jednak teraz trzeba przekazać go argument BytesRef, a jej całkowicie jasne, co Państwo mają do czynienia z wartością obok więc zamiast zmieniłem go (praca w toku)

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

która wydawała neater

w 3.6 Dodam przesłonić queryparser aby pracować dla numerycznych wyszukiwań zasięgu,

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

} 

Więc wziąłem to wszystko na zastanawianie nie zrobił tego potrzebują więcej, ale niestety nie ma pytania dotyczące tego IntField obecnie pracuje.

Dalsze czytanie wygląda na to, że Intfieldy są używane tylko dla zapytań o zakres, więc nie wiem, w jaki sposób należy po prostu dopasowywać zapytania i czy NumericRangeQuery jest kompatybilny z klasycznym analizatorem zapytań, którego używam.

Więc potem wrócił do próbując dodać moje wartości numeryczne jako zakodowany ciąg

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

Ale w czasie wykonywania Jestem teraz coraz błąd!

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

Ale muszę pola indeksu, więc jak mogę indeks pola numeryczne jak ja w 3.6 więc można je wyszukiwać.

Odpowiedz

1

Wystarczy użyć odpowiedniego pola. Na przykład IntField, LongField itp

Patrz np http://lucene.apache.org/core/4_1_0/core/org/apache/lucene/document/IntField.html

dla zapytań tych pól, patrz Lucene LongField exact search with Query

+0

Ale jeśli korzystasz z IntField, w jaki sposób mogę rozszerzyć QueryParser o przeszukiwanie takich pól? –

+1

Powoduje zwrócenie odpowiedniego parametru NumericRangeQuery z analizowanych wartości do liczby całkowitej. Tak więc, zamiast zwracania TermQuery, zwróć numericRangeQuery w metodzie newTermQuery, jeśli to konieczne. – RobAu

0

Mam to działa, niezależnie od tego, czy jest to najlepszy sposób robienia rzeczy, których nie znam.

  1. Dodawanie numeru do indeksu jako ciąg

    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, musi sprawdzić nazwa_pola użyciu equals(), uprzednio mogła wystawać używać ==

    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. również podpis Zmieniono parametr newRangeQuery(), dodatkowy parametr 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. można uzyskać oryginalną wartość intgeral z indeksu następująco

    NumericUtils.prefixCodedToInt(new BytesRef(code)) 
    
2

Zaledwie heads-up, w jaki sposób to zrobić przy użyciu Lucene 4.7:

Kiedy indeksowanie po prostu zrobić jak folows:

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

A do wyboru:

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

}

Robiąc tak, querys jak

int_field: 1 
int_field: [1 TO 5] 

działa zgodnie z oczekiwaniami.