java - 为什么我的短语查询给我的结果这么少?

标签 java sorting search indexing lucene

我想用Lucene(4.10版)处理几百万的新闻数据。我对 Lucene 很陌生,所以我想越来越多地了解它是如何工作的。在每个 lucene 文档中,我都存储一篇新闻文章。每篇文章当然都有其内容(字段称为“TextContent”)。

我这样创建字段(与 this stackoverflow 问题相关):

/* Indexed, tokenized, stored. */
public static final FieldType TYPE_STORED = new FieldType();

static {
    TYPE_STORED.setIndexed(true);
    TYPE_STORED.setTokenized(true);
    TYPE_STORED.setStored(true);
    TYPE_STORED.setStoreTermVectors(true);
    TYPE_STORED.setStoreTermVectorPositions(true);
    TYPE_STORED.freeze();
}

doc.add(new Field("TextContent", oneArticle.getTextContent(), TYPE_STORED));

我这样做是因为我也想保存文本内容术语 vector (用于创建短语查询,这样我就可以轻松检索一篇新闻文章的术语 vector 并使用其内容进行搜索其他相关文章)。

我现在想搜索一个或几个词(结合 boolean 子句 Occur.SHOULD 或 MUST)

我的代码看起来像这样(words 只是一个包含所有要搜索的术语的列表)

IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(PATH_TO_INDEX)));
IndexSearcher searcher = new IndexSearcher(reader);

BooleanQuery booleanQuery = new BooleanQuery();

//words is simply a List<String> containing all terms to search for
for (String word : words) {
    PhraseQuery query = new PhraseQuery();
    query.add(new Term("TextContent", word));
    booleanQuery.add(query, BooleanClause.Occur.SHOULD);
}

//collects the results via scoring them using a Similarity Function 
TopScoreDocCollector collector = TopScoreDocCollector.create(reader.numDocs(), true);
searcher.search(booleanQuery, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;

System.out.println(hits.length);

for(int i = 0; i < 10; i++){
    int id = hits[i].doc;
    Document d = searcher.doc(id); 

    System.out.println(d.get("TextContent"));
}

我时不时地得到结果,但还不够,而且只针对非常流行的搜索词(例如,“足球”作为搜索词为我提供了 15000 篇文章,而有数百万篇新闻文章)。

当我搜索我的 textContent 字段中包含的不太流行的术语时,我得到 0 个结果。例如,我有一个文本内容开头的文档:

"Sonny Bill Williams will reunite with former All Blacks captain Tana Umaga [..]. The 29-year-old dual rugby international [...]"

如果我只知道在我的列表词中添加“橄榄球”这个词,我会得到 4125 个结果,在前 10 名中还有我刚刚引用的文章。如果我只添加单词“Williams”(作为这位橄榄球运动员的名字——参见上面的引述),我会得到 0 个结果。

我不明白这种行为。我推测它必须处理我如何在我的 Lucene 索引中创建“TextContent”字段的事实。正在进行的谷歌研究让我想到了其他几个 stackoverflow 问题(例如 herehere )。我的问题的不同之处在于,我会不时获得结果,但仅限于非常流行的术语。

你能告诉我我做错了什么吗?你能告诉我应该如何改变我的 TextContent Field/FieldType 以提供更好的结果吗?或者我应该如何更改我的查询?

非常感谢您的每一个回答,并认为您正在与我分享。

更新:新知识到来

来自 this stackoverflow 问题 我想到尝试使用“williams”(全部小写)而不是“Williams”。其中一个答案的引述是:

The reason why you don't get your documents back is that while indexing you're using StandardAnalyzer, which converts tokens to lowercase and removes stop words.

这成功了。如果我把所有东西都写成小写,我就会得到结果。我还用 Luke 检查了我的索引,发现我的词 vector 中的所有词都被转换为小写。我现在将把这个更新留在这里,并为更多可能的答案留出空间(也许仍然有问题/需要改进以获得更好的结果)。如果没有收到任何答案,我稍后会将其发布为我的答案。

最佳答案

听起来您已经找到了问题的原因。处理此问题的另一种选择是,您可以在使用 QueryParser 构建查询时应用相同的分析器。如果您正在获取用户输入的短语,然后以某种方式对其进行解析以获取变量 words,那么这可能是一种更简单、更可靠的处理方式:

QueryParser parser = new QueryParser("TextContent", new StandardAnalyzer());
//if you are actually looking for a phrase
Query queryPhrase = parser.parse("\"" + inputPhrase + "\"");
//if instead you want independant term queries
Query queryTerms = parser.parse(inputPhrase);

另外请注意,构造一个只有一个词项的 PhraseQuery 没有多大意义。我不确定您要查找以下哪些内容:

for (String word : words) {
    TermQuery query = new TermQuery(new Term("TextContent", word));
    booleanQuery.add(query, BooleanClause.Occur.SHOULD);
}

或者:

PhraseQuery query = new PhraseQuery();
for (String word : words) {
    query.add(new Term("TextContent", word));
}
booleanQuery.add(query, BooleanClause.Occur.SHOULD);

关于java - 为什么我的短语查询给我的结果这么少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29030627/

相关文章:

java - Spring MVC 4 : "application/json" Content Type is not being set correctly

java - 对于 Java,是否有一个与我想要的完全匹配的分词器?

javascript - 拖放 Javascript 可通过移动标记进行排序?

使用整个单词在新的 Sitecore ContentSearch 中进行搜索

java - 搜索对象数组和索引位置

java - 在 Rest Assured 中发布多部分文件和 JSON

java - 无法运行 .jar 文件

javascript - 从 A-Z 顺序对数组内的对象进行排序

python - 在 python 中混合使用 switch 和 rotate 对数字进行排序

.net - 组织搜索服务的最佳方式,可以根据过滤器集在大数据库中查找数据