我的问题是如何使用Lucene解析通配符查询,查询字词是通过TokenFilter
传递的。
我正在使用带有多个文件管理器的自定义Analyzer
(例如ASCIIFoldingFilter
,但这只是一个示例)。我的问题是,只要Lucene的QueryParser
检测到其中一个子查询是WildcardQuery
,它按设计 [1]就会忽略Analyzer
。
这意味着über的查询已正确过滤,
über -> uber
但是对über*(带通配符)的查询根本没有通过过滤器:
über* -> über*
显然这意味着 - 作为索引端所有令牌都被过滤 - 在包含ü的任何查询中都可以有 no 匹配...
问:我如何强制Lucene过滤WildCard查询的查询?我正在寻找一种至少可以轻微重用Lucene代码库的方法; - )
注意:作为输入,我收到一个查询字符串,因此以编程方式构建查询不是一个选项。 注意:我正在使用Lucene 4.5.1。
[1] http://www.gossamer-threads.com/lists/lucene/java-user/14224
上下文:
// analyzer applies filters in Analyzer#createComponents (String, Reader)
Analyzer analyzer = new CustomAnalyzer (Version.LUCENE_45);
// I'm using org.apache.lucene.queryparser.classic.MultiFieldQueryParser
QueryParser parser = new MultiFieldQueryParser (Version.LUCENE_45, fields, analyzer);
parser.setAllowLeadingWildcard (true);
parser.setMultiTermRewriteMethod (MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
// actual parsing of the input query
Query query = parser.parse (input);
答案 0 :(得分:1)
好的,我找到了一个解决方案:我正在推广QueryParser
以覆盖#getWildcardQuery (String, String)
。通过这种方式,我可以在检测到通配符查询之后和创建之前拦截并更改该术语:
@Override
protected Query getWildcardQuery (String field, String termStr) throws ParseException
{
String term = termStr;
TokenStream stream = null;
try
{
// we want only a single token and we don't want to lose special characters
stream = new KeywordTokenizer (new StringReader (term));
stream = new LowerCaseFilter (Version.LUCENE_45, stream);
stream = new ASCIIFoldingFilter (stream);
CharTermAttribute charTermAttribute = stream.addAttribute (CharTermAttribute.class);
stream.reset ();
while (stream.incrementToken ())
{
term = charTermAttribute.toString ();
}
}
catch (IOException e)
{
LOGGER.debug ("Failed to filter search query token {}", term, e);
}
finally
{
IOUtils.closeQuietly (stream);
}
return super.getWildcardQuery (field, term);
}
此解决方案基于类似的问题:
Using a Combination of Wildcards and Stemming
How to get a Token from a Lucene TokenStream?
注意:在我的代码中,将所有过滤器保留在单个位置实际上有点复杂......
但我仍然认为应该有更好的解决方案。