#xml #lucene #information-retrieval
#xml #lucene #поиск информации
Вопрос:
У меня есть корпус документов, которые выглядят следующим образом:
<doc>
text sample text <x>text</x> words lipsum words words <x>text</x> some other text
</doc>
Я хотел бы иметь возможность искать фразы (в «»), которые встречаются в определенном количестве токенов из аннотации. Как я могу индексировать и выполнять поиск подобным образом?
Комментарии:
1. Что вы подразумеваете под «которые встречаются в пределах определенного количества токенов из аннотации»? (что вы называете аннотацией, в частности). Приведите более подробный пример того, чего вы хотите достичь (примеры входных данных, выходов).
2. В приведенном выше примере запрос «lipsum words» в пределах двух токенов (слов) <x> вернул бы совпадение, но «другой текст» с тем же условием не вернул бы. Другой способ формулировки запроса — сказать, что я хочу ограничить свой поиск документами, в которых строка поиска находится рядом с <x></x>
3. @LeonDerczynski разве вы не можете просто обрезать документы и проиндексировать только эти части?
Ответ №1:
Вы могли бы использовать пользовательский анализатор для анализа вашего XML-потока. Я взломал тот, который разбивается на пробелы, ‘>’ и ‘/’, так что XML-токены идентифицируются с помощью ‘
public class SpanQueryTests {
private IndexSearcher searcher;
private IndexReader reader;
private Analyzer analyzer;
static class XMLTokenizer extends CharTokenizer {
public XMLTokenizer(Reader input) {
super(input);
}
final static Set<Character> chars = ImmutableSet.of('/', '>');
@Override
protected boolean isTokenChar(char c) {
return !(Character.isWhitespace(c) || chars.contains(c));
}
}
@Before
public void setUp() throws Exception {
Directory dir = new RAMDirectory();
analyzer = new Analyzer() {
@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
return new XMLTokenizer(reader);
}
@Override
public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
Tokenizer tokenizer = (Tokenizer) getPreviousTokenStream();
if (tokenizer == null) {
tokenizer = new XMLTokenizer(reader);
setPreviousTokenStream(tokenizer);
} else
tokenizer.reset(reader);
return tokenizer;
}
};
IndexWriter writer = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
ImmutableList<String> docs = ImmutableList.of("<doc>text sample text <x>test</x> words lipsum words words "
"<x>text</x> some other text </doc>",
"<foobar>test</foobar> some more text flop");
int id = 0;
for (String content: docs) {
Document doc = new Document();
doc.add(new Field("id", String.valueOf(id ), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("content", content, Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
id ;
}
writer.close();
searcher = new IndexSearcher(dir);
reader = searcher.getIndexReader();
}
@After
public void tearDown() throws Exception {
searcher.close();
}
@Test
public void testTermNearQuery() throws Exception {
SpanTermQuery tq1 = new SpanTermQuery(new Term("content", "lipsum"));
dumpSpans(tq1);
SpanTermQuery tq2 = new SpanTermQuery(new Term("content", "other"));
dumpSpans(tq2);
SpanTermQuery tq3 = new SpanTermQuery(new Term("content", "<x"));
dumpSpans(tq3);
SpanNearQuery snq1 = new SpanNearQuery(new SpanQuery[] { tq1, tq3 }, 2, false);
dumpSpans(snq1);
SpanNearQuery snq2 = new SpanNearQuery(new SpanQuery[] { tq2, tq3 }, 2, false);
dumpSpans(snq2);
}
}
Результаты таковы:
query content:lipsum
<doc text sample text <x test< x words <lipsum> words words <x text< x some other text < doc (0.15467961)
query content:other
<doc text sample text <x test< x words lipsum words words <x text< x some <other> text < doc (0.15467961)
query content:<x
<doc text sample text <<x> test< x words lipsum words words <x text< x some other text < doc (0.21875)
<doc text sample text <x test< x words lipsum words words <<x> text< x some other text < doc (0.21875)
query spanNear([content:lipsum, content:<x], 2, false)
<doc text sample text <x test< x words <lipsum words words <x> text< x some other text < doc (0.19565594)
query spanNear([content:other, content:<x], 2, false)
NO spans