我们可以在语音索引中使用SpanNearQuery吗?

时间:2016-07-29 14:03:13

标签: lucene full-text-search

我已经实现了一个基于lucene的软件来索引超过一千万个人的名字,这些名字可以用不同的方式写成,如“Luíz”和“Luis”。索引是使用相应标记的语音值创建的(创建了自定义分析器)。

目前,我正在使用QueryParser查询具有良好结果的给定名称。但是,在“Lucene in Action”一书中提到SpanNearQuery可以使用令牌的接近度来改进我的查询。我使用SpanNearQuery对抗非语音的名称索引,结果与QueryParser相比更优越。

由于我们应该使用相同的分析器进行查询,我无法找到如何同时使用我的自定义语音分析器和SpanNearQuery,或者改写:

    how can I use SpanNearQuery on the phonetic index?

提前致谢。

1 个答案:

答案 0 :(得分:1)

我的第一个想法是:用slop进行短语查询是不是可以完成这项工作?那肯定是最简单的方法:

"term1 term2"~5

这将使用您的语音分析器,并使用生成的标记生成邻近查询。

所以,如果你真的需要在这里使用SpanQueries(也许你正在使用模糊查询或通配符或其他类似的东西,或者PhraseQuery一直在威胁你,你想要的更多与它),你需要自己做分析。您可以通过从Analyzer.tokenStream获取TokenStream并迭代分析的标记来完成此操作。

如果您使用的是每个术语生成单个代码的语音算法(例如soundex):

SpanNearQuery.Builder nearBuilder = new SpanNearQuery.Builder("text", true);
nearBuilder.setSlop(4);

TokenStream stream = analyzer.tokenStream("text", queryStringToParse);
stream.addAttribute(CharTermAttribute.class);
stream.reset();
while(stream.incrementToken()) {
    CharTermAttribute token = stream.getAttribute(CharTermAttribute.class);
    nearBuilder.addClause(new SpanTermQuery(new Term("text", token.toString())));
}
Query finalQuery = nearBuilder.build();
stream.close();

如果您使用的是双联想电话,在同一位置可以有1-2个术语,那么它会更复杂,因为您需要考虑这些位置增量:

SpanNearQuery.Builder nearBuilder = new SpanNearQuery.Builder("text", true);
nearBuilder.setSlop(4);

TokenStream stream = analyzer.tokenStream("text", "through and through");
stream.addAttribute(CharTermAttribute.class);
stream.addAttribute(PositionIncrementAttribute.class);
stream.reset();
String queuedToken = null;
while(stream.incrementToken()) {
    CharTermAttribute token = stream.getAttribute(CharTermAttribute.class);
    PositionIncrementAttribute increment = stream.getAttribute(PositionIncrementAttribute.class);

    if (increment.getPositionIncrement() == 0) {
        nearBuilder.addClause(new SpanOrQuery(
                new SpanTermQuery(new Term("text", queuedToken)),
                new SpanTermQuery(new Term("text", token.toString()))
                ));
        queuedToken = null;
    }
    else if (increment.getPositionIncrement() >= 1 && queuedToken != null) {
        nearBuilder.addClause(new SpanTermQuery(new Term("text", queuedToken)));
        queuedToken = token.toString();
    }
    else {
        queuedToken = token.toString();
    }
}

if (queuedToken != null) {
    nearBuilder.addClause(new SpanTermQuery(new Term("text", queuedToken)));
}

Query finalQuery = nearBuilder.build();
stream.close();