Для удовольствия и обучения я пытаюсь создать тег POS для Open-LP и Lucene 7.4. Цель состоит в том, чтобы после индексации я действительно мог найти последовательность POS-тегов и найти все предложения, которые соответствуют последовательности. Я уже получил часть индексации, но я застрял в части запроса. Я знаю, что SolR может иметь некоторую функциональность для этого, и я уже проверил код (который, в конце концов, не был настолько самоуверенным). Но моя цель - понять и реализовать в Lucene 7, а не в SolR, так как я хочу быть независимым от любой поисковой системы сверху.
Идея
Введите предложение 1: Быстрая коричневая лиса перепрыгнула через ленивых собак.
Прикладной токенайзер Lucene OpenNLP приводит к: [The] [быстрый] [коричневый] [лиса] [перепрыгнул] [над] [the] [ленивый] [собаки] [.]
Далее, применение тегов POS Lucene OpenNLP приводит к: [DT] [JJ] [JJ] [NN] [VBD] [IN] [DT] [JJ] [NNS] [.]
Введите предложение 2: Дайте это мне, детка!
Применение токенайзера Lucene OpenNLP приводит к: [Give] [it] [to] [me] [,] [baby] [!]
Затем, применение тегов POS Lucene OpenNLP приводит к: [VB] [PRP] [TO] [PRP] [,] [UH] [.]
Запрос: JJ NN VBD соответствует части предложения 1, поэтому предложение 1 должно быть возвращено. (На данный момент меня интересуют только точные совпадения, т.е. давайте оставим в стороне частичные совпадения, символы подстановки и т. Д.)
Индексация
Сначала я создал свой собственный класс com.example.OpenNLPAnalyzer:
public class OpenNLPAnalyzer extends Analyzer {
protected TokenStreamComponents createComponents(String fieldName) {
try {
ResourceLoader resourceLoader = new ClasspathResourceLoader(ClassLoader.getSystemClassLoader());
TokenizerModel tokenizerModel = OpenNLPOpsFactory.getTokenizerModel("en-token.bin", resourceLoader);
NLPTokenizerOp tokenizerOp = new NLPTokenizerOp(tokenizerModel);
SentenceModel sentenceModel = OpenNLPOpsFactory.getSentenceModel("en-sent.bin", resourceLoader);
NLPSentenceDetectorOp sentenceDetectorOp = new NLPSentenceDetectorOp(sentenceModel);
Tokenizer source = new OpenNLPTokenizer(
AttributeFactory.DEFAULT_ATTRIBUTE_FACTORY, sentenceDetectorOp, tokenizerOp);
POSModel posModel = OpenNLPOpsFactory.getPOSTaggerModel("en-pos-maxent.bin", resourceLoader);
NLPPOSTaggerOp posTaggerOp = new NLPPOSTaggerOp(posModel);
// Perhaps we should also use a lower-case filter here?
TokenFilter posFilter = new OpenNLPPOSFilter(source, posTaggerOp);
// Very important: Tokens are not indexed, we need a store them as payloads otherwise we cannot search on them
TypeAsPayloadTokenFilter payloadFilter = new TypeAsPayloadTokenFilter(posFilter);
return new TokenStreamComponents(source, payloadFilter);
}
catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
Обратите внимание, что мы используем TypeAsPayloadTokenFilter, обернутый вокруг OpenNLPPOSFilter. Это означает, что наши POS-теги будут проиндексированы как полезные нагрузки, и наш запрос - как бы он ни выглядел - должен будет также выполнять поиск по полезным нагрузкам.
* 1025 Запросы *
Вот где я застрял. Я понятия не имею, как запросить полезные нагрузки, и все, что я пытаюсь, не работает. Обратите внимание, что я использую Lucene 7, похоже, что в старых версиях запросы на полезную нагрузку менялись несколько раз. Документация крайне скудная. Даже не ясно, какое имя поля теперь нужно запрашивать - это «слово» или «тип» или что-то еще? Например, я пробовал этот код, который не возвращает результатов поиска:
// Step 1: Indexing
final String body = "The quick brown fox jumped over the lazy dogs.";
Directory index = new RAMDirectory();
OpenNLPAnalyzer analyzer = new OpenNLPAnalyzer();
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
IndexWriter writer = new IndexWriter(index, indexWriterConfig);
Document document = new Document();
document.add(new TextField("body", body, Field.Store.YES));
writer.addDocument(document);
writer.close();
// Step 2: Querying
final int topN = 10;
DirectoryReader reader = DirectoryReader.open(index);
IndexSearcher searcher = new IndexSearcher(reader);
final String fieldName = "body"; // What is the correct field name here? "body", or "type", or "word" or anything else?
final String queryText = "JJ";
Term term = new Term(fieldName, queryText);
SpanQuery match = new SpanTermQuery(term);
BytesRef pay = new BytesRef("type"); // Don't understand what to put here as an argument
SpanPayloadCheckQuery query = new SpanPayloadCheckQuery(match, Collections.singletonList(pay));
System.out.println(query.toString());
TopDocs topDocs = searcher.search(query, topN);
Любая помощь очень ценится здесь.