【问题标题】:Lucene BooleanQuery wrong resultLucene BooleanQuery 错误结果
【发布时间】:2017-06-20 23:12:14
【问题描述】:

我创建了一个 Lucene RAMDirectory 来收集来自不同来源的数据并使其可快速搜索。我花了很多时间来了解不同的分析器和索引策略,但在某些情况下查询结果不是预期的。

这是一个演示类:

class LuceneDemo {

    static final String ANIMAL = "animal";
    static final String PERSON = "person";

    private StandardAnalyzer analyzer = new StandardAnalyzer();

    private IndexSearcher searcher;
    private IndexWriter writer;

    LuceneDemo() {
        Directory ramDirectory = new RAMDirectory();
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        try {
            writer = new IndexWriter(ramDirectory, config);

            addDocument(createDocument(PERSON, "DR-(frankenstein)"));
            addDocument(createDocument(ANIMAL, "gray fox"));
            addDocument(createDocument(ANIMAL, "island fox"));

            writer.close();
            IndexReader reader = DirectoryReader.open(ramDirectory);
            searcher = new IndexSearcher(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Document createDocument(String type, String value) {
        Document document = new Document();
        document.add(new TextField("type", type, Field.Store.YES));
        document.add(new TextField("name", value, Field.Store.YES));
        document.add(new StringField("name", value, Field.Store.YES));
        return document;
    }

    private void addDocument(Document document) {
        try {
            writer.addDocument(document);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    List<String> getDocuments(String type, String value) {
        value = "*" + QueryParser.escape(value) + "*";
        try {
            QueryParser queryParser = new QueryParser("name", analyzer);
            queryParser.setAllowLeadingWildcard(true);
            queryParser.setDefaultOperator(QueryParser.Operator.AND);

            BooleanQuery.Builder query = new BooleanQuery.Builder();
            query.add(new TermQuery(new Term("type", type)), BooleanClause.Occur.MUST);
            query.add(queryParser.parse(value), BooleanClause.Occur.MUST);

            TopDocs docs = searcher.search(query.build(), 10);

            return Arrays.stream(docs.scoreDocs).map(scoreDoc -> {
                try {
                    return searcher.doc(scoreDoc.doc).get("name");
                } catch (IOException e) {
                    return "";
                }
            }).collect(Collectors.toList());
        } catch (ParseException | IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }
}

如果我搜索“ox”、“gray fox”或“-(frankenstein)”,代码运行良好。但我没有“DR-(弗兰肯斯坦)”的结果。我不知道我做错了什么。因此,欢迎提出任何建议。

// OK
luceneDemo.getDocuments(LuceneDemo.ANIMAL, "ox").forEach(System.out::println);
luceneDemo.getDocuments(LuceneDemo.ANIMAL, "gray fox").forEach(System.out::println);
luceneDemo.getDocuments(LuceneDemo.PERSON, "-(frankenstein)").forEach(System.out::println);

// NOT OK
luceneDemo.getDocuments(LuceneDemo.PERSON, "DR-(frankenstein)").forEach(System.out::println);

【问题讨论】:

    标签: java lucene booleanquery standardanalyzer ramdirectory


    【解决方案1】:

    这就是您的文档的索引方式 -

    1. doc#1 type:person name:dr name:frankenstein name:DR-(frankenstein) (注意: StringField 未标记化,未转换为小写)
    2. doc#2 type:animal name:gray name:fox name:gray fox
    3. doc#3 type:animal name:island name:fox name:island fox

    基本上StringField 索引字段与analyzer 无关 - 没有标记化,并降低大小写。而读者使用StandardAnalyzer 并降低所有搜索的大小写。 因此,搜索“DR-(frankenstein)”会搜索不匹配的“dr-(frankenstein)”。

    要使您的代码使用 StandardAnalyzer 工作,您需要将 StringField 索引为小写。

    document.add(new StringField("name", value.toLowerCase(), Field.Store.YES));
    

    【讨论】:

    • 谢谢达库拉!我创建了一个自定义分析器并将字符串字段索引为小写。现在我得到了正确的结果!
    猜你喜欢
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多