首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lucene:多词短语作为搜索词

Lucene:多词短语作为搜索词
EN

Stack Overflow用户
提问于 2012-01-30 23:31:51
回答 4查看 25.6K关注 0票数 9

我正在尝试使用Apache Lucene创建一个可搜索的电话/本地业务目录。

我有街道名称,企业名称,电话号码等字段。我遇到的问题是,当我尝试搜索街道名称中包含多个单词的街道时(例如,'the returned‘),没有返回任何结果。但如果我只搜索一个单词,例如“新月”,我会得到所有我想要的结果。

我使用以下内容对数据进行索引:

代码语言:javascript
复制
String LocationOfDirectory = "C:\\dir\\index";

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_34);
Directory Index = new SimpleFSDirectory(LocationOfDirectory);

IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE.34, analyzer);
IndexWriter w = new IndexWriter(index, config);


Document doc = new Document();
doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Analyzed);

w.add(doc);
w.close();

我的搜索是这样的:

代码语言:javascript
复制
int numberOfHits = 200;
String LocationOfDirectory = "C:\\dir\\index";
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true);
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory));
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory);

WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent");

searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;

我尝试将通配符查询替换为短语查询,首先使用整个字符串,然后在空格中拆分字符串,并将它们包装在一个BooleanQuery中,如下所示:

代码语言:javascript
复制
String term = "the crescent";
BooleanQuery b = new BooleanQuery();
PhraseQuery p = new PhraseQuery();
String[] tokens = term.split(" ");
for(int i = 0 ; i < tokens.length ; ++i)
{
    p.add(new Term("Street", tokens[i]));
}
b.add(p, BooleanClause.Occur.MUST);

然而,这并不起作用。我尝试使用KeywordAnalyzer而不是StandardAnalyzer,但随后所有其他类型的搜索也停止工作。我尝试用其他字符(+和@)替换空格,并将查询转换为这种形式,但仍然不起作用。我认为它不起作用,因为+和@是没有索引的特殊字符,但是我似乎在任何地方都找不到像这样的字符的列表。

我开始有点发疯了,有人知道我做错了什么吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-02-01 01:34:50

我发现我尝试在不使用QueryParser的情况下生成查询是行不通的,因此我不再尝试创建我自己的查询,而是使用QueryParser。我在网上看到的所有建议都表明,您应该在QueryParser中使用与索引过程中使用的相同的分析器,因此我使用StandardAnalyzer来构建QueryParser。

这在本例中是有效的,因为在索引过程中,StandardAnalyzer从街道的“新月”中删除了单词" the“,因此我们无法搜索它,因为它不在索引中。

但是,如果我们选择搜索"Grove Road",就会遇到开箱即用功能的问题,即查询将返回包含"Grove“或"Road”的所有结果。这很容易解决,只需设置QueryParser,使其默认操作为AND而不是OR。

最后,正确的解决方案如下:

代码语言:javascript
复制
int numberOfHits = 200;
String LocationOfDirectory = "C:\\dir\\index";
TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true);
Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory));
IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory);

StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_35);

//WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent");
QueryParser qp = new QueryParser(Version.LUCENE_35, "Street", analyzer);
qp.setDefaultOperator(QueryParser.Operator.AND);

Query q = qp.parse("grove road");

searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
票数 7
EN

Stack Overflow用户

发布于 2012-01-31 06:31:33

没有取回文档的原因是在索引时使用的是StandardAnalyzer,它将标记转换为小写并删除停用的单词。因此,对于您的示例,唯一被索引的术语是“新月”。但是,通配符查询不会被分析,因此' the‘被作为查询的强制部分包括在内。在您的场景中,短语查询也是如此。

KeywordAnalyzer可能不太适合您的用例,因为它将整个字段内容作为单个令牌。您可以对街道字段使用SimpleAnalyzer --它将对所有非字母字符进行输入拆分,然后将它们转换为小写。您还可以考虑在LowerCaseFilter中使用WhitespaceAnalyzer。您需要尝试不同的选项,并找出最适合您的数据和用户的选项。

此外,如果更改该字段的分析器会中断其他搜索,则可以对每个字段使用不同的分析器(例如,使用PerFieldAnalyzerWrapper)。

票数 15
EN

Stack Overflow用户

发布于 2012-01-31 12:28:31

如果你想要一个与街道完全匹配的单词,你可以设置字段“街道”NOT_ANALYZED,它不会过滤停用的单词" the“。

代码语言:javascript
复制
doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Not_Analyzed);
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9066347

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档