2014-06-23 2 views
1

Я пересматриваю свой код, который был первоначально написан для Lucene 3.0 (я тогда обновил его, чтобы он работал в 4.0, но еще не воспользовался всеми улучшениями 4.0) ,Простейший способ разрешить запросы на числовые поля в Lucene 4

Для числовых полей, которые я хочу, чтобы иметь возможность делать запросы диапазона для добавить поле в документ следующим образом:

BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
NumericUtils.intToPrefixCoded(value, 0, bytes); 
doc.add(new Field(fieldname, bytes.utf8ToString(), 
    new FieldType(StringField.TYPE_NOT_STORED))); 

Тогда я должен иметь анализатор пользовательских запросов Переопределение методов newTermQuery() и новый RangeQuery()

т.е.

public class ReleaseQueryParser extends MultiFieldQueryParser 
{ 

    public ReleaseQueryParser(String[] strings, Analyzer a) 
    { 
     super(LuceneVersion.LUCENE_VERSION, strings, a); 
    } 

    protected Query newTermQuery(Term term) 
    { 
     if (
       (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) || 
         (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) || 
         (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.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); 

     } 
    } 

    @Override 
    public Query newRangeQuery(String field, 
           String part1, 
           String part2, 
           boolean startInclusive, 
           boolean endInclusive) 
    { 
     if (
       (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) || 
         (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) || 
         (field.equals(ReleaseIndexField.NUM_MEDIUMS.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; 

    } 
} 

Я всегда думал, что этот код довольно неуклюжим, и было интересно, если это можно было бы теперь несколько упростить?

Обновление

Пытались использовать IntField следующим

doc.add (новый IntField (field.getName(), значение, новый FieldType (StringField.TYPE_NOT_STORED)));

Составитель хорошо, но мой тестовый метод построения индекса

Fields fields = MultiFields.getFields(ir); 
Terms terms = fields.terms(field.getName()); 
TermsEnum termsEnum = terms.iterator(null); 
termsEnum.next(); 
assertEquals(value, NumericUtils.prefixCodedToInt(termsEnum.term())); 

терпит неудачу с NullPointerException на terms.iterator линии().

Изменен

doc.add(new IntField(field.getName(), value, new FieldType(IntField.TYPE_NOT_STORED))); 

и работал, но Im удивлён, что эта линия

NumericUtils.prefixCodedToInt(termsEnum.term()) 

все еще работает, я думаю IntField это просто обертка вокруг кода ByteRef я первоначально имел.

Затем переписал QueryParser следующего

public class ReleaseQueryParser extends MultiFieldQueryParser 
{ 

    public ReleaseQueryParser(String[] strings, Analyzer a) 
    { 
     super(LuceneVersion.LUCENE_VERSION, strings, a); 
    } 

    protected Query newTermQuery(Term term) 
    { 
     if (
       (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) || 
         (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) || 
         (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.getName())) 
       ) 
     { 
      return NumericRangeQuery.newIntRange(term.field(), Integer.parseInt(term.text()), Integer.parseInt(term.text()), true, true); 
     } 
     else 
     { 
      return super.newTermQuery(term); 

     } 
    } 

    @Override 
    public Query newRangeQuery(String field, 
           String part1, 
           String part2, 
           boolean startInclusive, 
           boolean endInclusive) 
    { 
     if (
       (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) || 
         (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) || 
         (field.equals(ReleaseIndexField.NUM_MEDIUMS.getName())) 
       ) 
     { 
      return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2),startInclusive, endInclusive); 
     } 
     else 
     { 
      return super.newRangeQuery(field, part1, part2, startInclusive, endInclusive); 
     } 
    } 
} 

и работал, я действительно не хочу, чтобы использовать запрос диапазона в пределах newTermQuery (срок срока), но я не мог видеть более простой способ.

ответ

0

Используйте классы IntField или LongField, предоставляемые lucene. Затем вы можете просто запросить индекс, используя стандарт NumericRangeQuery указанного типа

+0

спасибо, что у меня есть улучшенное решение на основе вашей информации, хотя, возможно, это место для дальнейшего совершенствования. –

Смежные вопросы