当前位置: 首页 > 知识库问答 >
问题:

使用Lucene 7 OpenNLP查询词性标签

嵇丰
2023-03-14

为了好玩和学习,我正在尝试用OpenNLP和Lucene 7.4构建一个词性(POS)标记器。目标是,一旦建立索引,我就可以搜索一系列的词性标签,并找到所有符合序列的句子。我已经得到了索引部分,但我被困在查询部分。我知道SolR可能有一些这方面的功能,我已经检查了代码(这毕竟不是自我解释的)。但我的目标是在Lucene 7中理解和实现,而不是在SolR中,因为我想独立于任何顶级搜索引擎。

想法输入句子1:敏捷的棕色狐狸跳过了懒惰的狗。Applied Lucene OpenNLP tokenizer的结果是:[The][quick][brown][fox][hipped][over][The][lazy][dogs][.]接下来,在[DT][JJ][JJ][NN][VBD][in][DT][JJ][NNS][中应用Lucene OpenNLP词性标注结果

输入句子2:给我,宝贝!Applied Lucene OpenNLP tokenizer的结果是:[Give][it][to][me][,][baby][!]接下来,在[VB][PRP][TO][PRP][,][UH][中应用Lucene OpenNLP词性标注结果

查询:JJ NN VBD匹配句子1的一部分,所以应该返回句子1。(此时,我只对精确匹配感兴趣,也就是说,让我们撇开部分匹配、通配符等。)

首先,我创建了自己的类com。实例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());
    }              

}

请注意,我们使用的是围绕OpenNLPPOSFilter的TypeAsPayloadTokenFilter。这意味着,我们的POS标签将被索引为有效负载,我们的查询——不管它看起来如何——也必须搜索有效负载。

查询这就是我陷入困境的地方。我不知道如何查询有效负载,无论我尝试什么都不起作用。请注意,我使用的是Lucene 7,似乎在旧版本中查询有效负载已经更改了几次。文档极其稀缺。现在甚至不清楚要查询的正确字段名称是什么——是“word”还是“type”还是其他任何东西?例如,我尝试了这段不返回任何搜索结果的代码:

    // 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);

非常感谢您的帮助。

共有1个答案

赵雅懿
2023-03-14

为什么不使用TypeAsSynonymFilter而不是TypeAsPayloadTokenFilter,只做一个普通的查询呢。所以在你的分析器中:

:
TokenFilter posFilter = new OpenNLPPOSFilter(source, posTaggerOp);
TypeAsSynonymFilter typeAsSynonymFilter = new TypeAsSynonymFilter(posFilter);
return new TokenStreamComponents(source, typeAsSynonymFilter);

索引方面:

static Directory index() throws Exception {
  Directory index = new RAMDirectory();
  OpenNLPAnalyzer analyzer = new OpenNLPAnalyzer();
  IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
  IndexWriter writer = new IndexWriter(index, indexWriterConfig);
  writer.addDocument(doc("The quick brown fox jumped over the lazy dogs."));
  writer.addDocument(doc("Give it to me, baby!"));
  writer.close();

  return index;
}

static Document doc(String body){
  Document document = new Document();
  document.add(new TextField(FIELD, body, Field.Store.YES));
  return document;
}

搜索端:

static void search(Directory index, String searchPhrase) throws Exception {
  final int topN = 10;
  DirectoryReader reader = DirectoryReader.open(index);
  IndexSearcher searcher = new IndexSearcher(reader);

  QueryParser parser = new QueryParser(FIELD, new WhitespaceAnalyzer());
  Query query = parser.parse(searchPhrase);
  System.out.println(query);

  TopDocs topDocs = searcher.search(query, topN);
  System.out.printf("%s => %d hits\n", searchPhrase, topDocs.totalHits);
  for(ScoreDoc scoreDoc: topDocs.scoreDocs){
    Document doc = searcher.doc(scoreDoc.doc);
    System.out.printf("\t%s\n", doc.get(FIELD));
  }
}

然后像这样使用它们:

public static void main(String[] args) throws Exception {
  Directory index = index();
  search(index, "\"JJ NN VBD\"");    // search the sequence of POS tags
  search(index, "\"brown fox\"");    // search a phrase
  search(index, "\"fox brown\"");    // search a phrase (no hits)
  search(index, "baby");             // search a word
  search(index, "\"TO PRP\"");       // search the sequence of POS tags
}

结果如下:

body:"JJ NN VBD"
"JJ NN VBD" => 1 hits
    The quick brown fox jumped over the lazy dogs.
body:"brown fox"
"brown fox" => 1 hits
    The quick brown fox jumped over the lazy dogs.
body:"fox brown"
"fox brown" => 0 hits
body:baby
baby => 1 hits
    Give it to me, baby!
body:"TO PRP"
"TO PRP" => 1 hits
    Give it to me, baby!
 类似资料:
  • 我是完全新的NLP的世界,我需要你的帮助开始标记阿拉伯语句子使用漂亮的斯坦福pos标签。 我已经安装了一个完整的版本,其中包含两个阿拉伯语培训的标签。 请指导我使用java和eclipse在阿拉伯语中应用此标记器, 我应该导入什么? 我该给模特们加些什么 处理阿拉伯语的函数和库 即使它不在训练集中,这个标记器也能给出正确的标记吗? 事实上,我已经浏览了斯坦福大学的官方网站,但它没有那么大的帮助 先

  • 问题内容: 我有一些文档的映射,并且查询agains条件确实失败。我不明白为什么: 例如,我可以对进行词条查询,效果很好 现在 对fwot同样失败 。怎么了? 问题答案: 您需要为此工作。并且您需要为数据重新索引以使上述更改生效。 这是映射更改和一些测试数据的命令的完整列表:

  • 环境是Java、Spring-boot、Hibernat、QueryDSL、MySQL。 我有表结构 艾碧索 更新 为了澄清起见,支持UI视图的DTO包含“casename”属性。它是在将域对象转换为DTO时在服务层创建的:

  • 上面是我的弹性查询,以获取属于服务器的所有记录,在时间范围内,我的数据集中有和列,但在错误下面抛出: {“error”:{“root_case”:[{“type”:“parsing_exception”,“reason”:“[term]格式错误的查询,预期[END_OBJECT]但找到[FIELD_NAME]”,“line”:9,“col”:11}],“type”:“parsing_excepti

  • 问题内容: 如果我有这样的字符串/短语存储在数据库中: 什么是Q型操作? 程序员指南 ABC的编码 有没有办法像传递的查询参数或或并将其找到,并? 问题答案: tsvector 使用类型,它是PostgreSQL文本搜索功能的一部分。 您也可以在tsvectors上使用熟悉的运算符: 从tsvector文档中: tsvector值是不同词素的排序列表,这些词素是已归一化以合并同一单词的不同变体的单

  • 问题内容: 我认为,对于上述查询,我​​只能将行插入到的值为的位置。但是,我能够插入除for以外的值。 问题: 为什么我们需要像上面这样的查询?使用它的现实生活场景是什么? 问题答案: 它基本上是一种允许更新视图的结构。对于多表方案,只能对基础表之一进行INSERT。视图和要插入的表之间必须存在一对一的关系。 您显示的查询是一个内联视图,扩展了相同的概念。 在这里阅读更多文档 http://doc