我想使用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));
我是这样做的,因为我想保存文本内容术语向量(用于创建短语查询,所以我可以例如轻松检索一篇新闻文章的术语向量并搜索其内容其他相关文章)。
我现在想要搜索一个或几个单词(结合布尔条款Occur.SHOULD或MUST)
我的代码看起来像这样(单词只是一个包含要搜索的所有术语的列表)
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"));
}
我不时获得结果,但不够,仅适用于非常受欢迎的搜索字词(例如&#34;足球&#34;搜索字词为我提供了15000篇文章,而有数百万条新闻文章)。
当我搜索textContent字段包含的不太流行的术语时,我得到0结果。例如,我有一个textcontent开头的文档:
&#34;桑尼比尔威廉姆斯将与前全黑队队长塔纳团聚 Umaga [..]。 29岁的双橄榄球国际赛[...]&#34;
如果我知道只添加&#34;橄榄球&#34;在我的List单词中,我得到4125个结果,在前10个也是我刚引用的文章。如果我只添加“#34; Williams&#34; (作为这个橄榄球运动员的名字 - 见上面的引用)我得到0结果。
我不明白这种行为。我猜测它必须处理我如何创建&#34; TextContent&#34;我的Lucene索引中的字段。正在进行的谷歌研究已经引出了我的其他几个stackoverflow问题(例如here和here)。与我的问题不同的是,我不时会得到结果,但仅限于非常受欢迎的术语。
你能告诉我我做错了什么吗?你能告诉我如何改变我的TextContent Field / FieldType来提供更好的结果吗?或者我该如何更改查询?非常感谢每一个答案,并认为你与我分享。
更新:新知识到达
从this stackoverflow问题我得到了尝试&#34;威廉姆斯&#34; (全部小写)代替&#34;威廉姆斯&#34;。其中一个答案的引用是:
你没有得到你的文件的原因是那时候 索引你使用StandardAnalyzer,它将令牌转换为 小写并删除停用词。
这很有用。如果我把所有东西写成小写,我会得到结果。我还用Luke检查了我的索引,发现我的术语向量中的所有术语都转换为小写。我现在将这个更新留在这里,并为更多可能的答案提供空间(可能仍然有问题/需要改进以获得更好的结果)。如果没有答案,我会稍后将其作为我的答案发布。
答案 0 :(得分:0)
听起来你已经找到了问题的原因。处理此问题的另一个选择是,在使用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);