我想用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 问题(例如 here 和 here )。我的问题的不同之处在于,我会不时获得结果,但仅限于非常流行的术语。
你能告诉我我做错了什么吗?你能告诉我应该如何改变我的 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/