Я пересматриваю свой код, который был первоначально написан для 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 (срок срока), но я не мог видеть более простой способ.
спасибо, что у меня есть улучшенное решение на основе вашей информации, хотя, возможно, это место для дальнейшего совершенствования. –