1

我们正在从搜索词字符串中构建一个布尔查询来搜索我们的 Lucene 索引。我希望使用标准分析器来分析这些字符串,标准分析器是我们用于索引的分析器。例如,foo-bar 1-2-3应该分解为foo, bar1-2-3因为 Lucene 文档指出连字符会导致数字保持在一起,但单词会被标记化。做这个的最好方式是什么?

目前我正在通过 QueryParser 运行我的搜索词字符串。

QueryParser parser = new QueryParser("", new StandardAnalyzer()); 
Query query = parser.parse(aSearchTermString);

这样做的问题是插入了引号。例如,foo-bar 1-2-3变成"foo bar", 1-2-3,它不会返回任何东西,因为 Lucene 会被标记foo-barfooand bar

我绝对不想通过删除引号来破解这种情况,replace因为我觉得我可能遗漏了一些东西或做错了一些事情。

4

1 回答 1

1

我实际上得到了不同的结果StandardAnalyzer。考虑这段代码(使用 Lucene v4):

public class Tokens {

    private static void printTokens(String string, Analyzer analyzer) throws IOException {
        System.out.println("Using " + analyzer.getClass().getName());
        TokenStream ts = analyzer.tokenStream("default", new StringReader(string));
        OffsetAttribute offsetAttribute = ts.addAttribute(OffsetAttribute.class);
        CharTermAttribute charTermAttribute = ts.addAttribute(CharTermAttribute.class);

        while(ts.incrementToken()) {
            int startOffset = offsetAttribute.startOffset();
            int endOffset = offsetAttribute.endOffset();
            String term = charTermAttribute.toString();
            System.out.println(term + " (" + startOffset + " " + endOffset + ")");
        }
        System.out.println();
    }

    public static void main(String[] args) throws IOException {
        printTokens("foo-bar 1-2-3", new StandardAnalyzer(Version.LUCENE_40));
        printTokens("foo-bar 1-2-3", new ClassicAnalyzer(Version.LUCENE_40));

        QueryParser standardQP = new QueryParser(Version.LUCENE_40, "", new StandardAnalyzer(Version.LUCENE_40));
        BooleanQuery q1 = (BooleanQuery) standardQP.parse("someField:(foo\\-bar\\ 1\\-2\\-3)");
        System.out.println(q1.toString() + "     # of clauses:" + q1.getClauses().length);
    }
}

上图:

Using org.apache.lucene.analysis.standard.StandardAnalyzer
foo (0 3)
bar (4 7)
1 (8 9)
2 (10 11)
3 (12 13)

Using org.apache.lucene.analysis.standard.ClassicAnalyzer
foo (0 3)
bar (4 7)
1-2-3 (8 13)

someField:foo someField:bar someField:1 someField:2 someField:3     # of clauses:5

因此,上面的代码证明StandardAnalyzer,与 example 不同ClassicAnalyzer,应该拆分1-2-3为不同的令牌 - 完全按照您的意愿。对于查询,你需要对每个关键字进行转义,包括空格,否则 QP 认为这有不同的含义。

如果您不想转义查询字符串,您始终可以手动标记它(如printTokens上面的方法),然后用 a 包装每个标记TermQuery并将所有 TermQueries 堆叠到 aBooleanQuery中。

于 2013-01-22T22:23:59.910 回答