Использование XML-полей для многократного поиска в Lucene

#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