Как искать поле int в Lucene 4?
Я пытаюсь реализовать индекс документов (грубо соответствующий строкам DB), где одно из полей является целым числом. Я добавляю их для индекса, например:
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);
Кажется, я вообще не могу запросить поле ticket_id
, а id_s
работает нормально.
Один из документов (я добавил пробел для чтения):
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>>
Таким образом, мое int-поле сохраняется, но не индексируется. Этот запрос работает как ожидалось: id_s:152
, в то время как этот никогда ничего не возвращает: ticket_id:152
.
Что я делаю неправильно? Как я могу добавить такое поле в индекс и сделать его доступным для поиска?
Ответы
Ответ 1
Ниже работает для меня:
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"
Как отметил femtoRgon, для числовых значений (длинные, даты, поплавки и т.д.) вам нужно иметь NumericRangeQuery
и указать точность. В противном случае Lucene не знает, как вы хотите определить сходство.
Ответ 2
Числовые поля можно запросить с помощью NumericRangeQuery. Для точного соответствия просто установите максимальные и минимальные значения равными.
Ваш вывод, указывающий, что поле не индексируется, может быть вызвано различиями в индексировании числового значения по сравнению с текстовым значением. Учитывая, что поле преобразуется в числовое представление Lucene, буквальное значение 152
действительно не будет индексироваться
Однако, с одной стороны, возможно, что ваша обработка id_s может быть лучшей альтернативой. Идентификаторы обычно не обрабатываются как числовые значения, а скорее как простые идентификаторы, которые представляются цифрами. Если вам не нужна численная сортировка или запрос диапазона в поле, индексирование как StringField
, безусловно, имеет больше смысла.
Ответ 3
Еще один ответ приходит из этого потока (третий ответ): Lucene 4.0 IndexWriter updateDocument для числового термина
В принципе, вы создаете термин с вашим значением int следующим образом:
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);
Затем вы можете использовать этот термин для поиска или удаления/обновления вашего индекса. В первом тесте это работало отлично для меня. Я не могу сказать, действительно ли это "правильный" способ сделать что-то. Я использовал NumericRangeFilter раньше для фильтрации IntFields, но теперь я склонен использовать этот подход и вместо этого использую обычные терминыFilter или TermQueries.