我使用StandardAnalyzer创建了一个Lucene索引,其中包含以下三个字段。
我正在使用下面的包装器类来简化编写布尔查询
public interface IQuery
{
BooleanQuery GetQuery();
}
public class QueryParam : IQuery
{
public string[] Fields { get; set; }
public string Term { get; set; }
private BooleanQuery _indexerQuery;
public QueryParam(string term, params string[] fields)
{
Term = term;
Fields = fields;
}
public BooleanQuery GetQuery()
{
_indexerQuery = new BooleanQuery();
foreach (var field in Fields)
_indexerQuery.Add(new FuzzyQuery(new Term(field, Term)), Occur.SHOULD);
return _indexerQuery;
}
}
public class AndQuery : IQuery
{
private readonly IList<IQuery> _queryParams = new List<IQuery>();
private BooleanQuery _indexerQuery;
public AndQuery(params IQuery[] queryParams)
{
foreach (var queryParam in queryParams)
{
_queryParams.Add(queryParam);
}
}
public BooleanQuery GetQuery()
{
_indexerQuery = new BooleanQuery();
foreach (var query in _queryParams)
_indexerQuery.Add(query.GetQuery(), Occur.MUST);
return _indexerQuery;
}
}
public class OrQuery : IQuery
{
private readonly IList<IQuery> _queryParams = new List<IQuery>();
private readonly BooleanQuery _indexerQuery = new BooleanQuery();
public OrQuery(params IQuery[] queryParams)
{
foreach (var queryParam in queryParams)
{
_queryParams.Add(queryParam);
}
}
public BooleanQuery GetQuery()
{
foreach (var query in _queryParams)
_indexerQuery.Add(query.GetQuery(), Occur.SHOULD);
return _indexerQuery;
}
public OrQuery AddQuery(IQuery query)
{
_queryParams.Add(query);
return this;
}
}
以下查询在Lucene.Net中没有给我任何结果,但是当我在Luke中搜索相同的查询时,它可以完美地运行。
var query = new AndQuery(new QueryParam(city.ToLower(), "city"), new QueryParam(state.ToLower(), "state"), new QueryParam(streetAddress.ToLower(), "streetname"));
执行query.GetQuery()
会在下面生成查询。
{+(城市:坦帕~0.5)+(州:fl~0.5)+(街道:网球场~0.5)}
答案 0 :(得分:1)
您可以使用BooleanQuery进行搜索。使用段中的空格分隔您的术语,然后创建查询并在索引中搜索。
EX: -
BooleanQuery booleanQuery = new BooleanQuery()
BooleanQuery searchTermQuery = new BooleanQuery();
foreach (var searchTerm in searchTerms)
{
var searchTermSegments = searchTerm.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
if (searchTermSegments.Count() > 1)
{
searchTermQuery.Clauses().Clear();
foreach (var SegTex in searchTermSegments)
{
searchTermQuery.Add( new FuzzyQuery(new Term("FieldName", SegTex.ToLower().Trim())),BooleanClause.Occur.MUST);
}
booleanQuery.Add(searchTermQuery, BooleanClause.Occur.MUST);
}
else
{
booleanQuery.Add(new FuzzyQuery(new Term("FieldName", searchTerm.ToLower().Trim())), BooleanClause.Occur.MUST);
}
}
答案 1 :(得分:0)
问题在于tennis court
的处理。您没有展示如何索引这些字段,但我会假设它们在索引中被标记化,例如使用StandardAnalyzer
之类的东西。这意味着,“网球场”将分为两个单独的术语“网球”和“球场”。但是,在手动创建FuzzyQuery时,没有分析或标记化,因此您只有一个术语“网球场”。 “网球场”和“网球”(6个编辑)或“法院”(7个编辑)之间有很大的编辑距离,所以它们都不匹配。
这里的混乱似乎是
+(city:tampa~0.5) +(state:fl~0.5) +(street:tennis court~0.5)
似乎工作。但是,假设用于调试的文本查询输出可以通过查询程序运行以生成相同的查询,这是不安全的,这是一个很好的例子。 QueryParser
语法根本无法表达您可以使用手动构造的查询执行的所有操作。通过查询解析器运行该查询将生成更类似的查询:
+(city:tampa~0.5) +(state:fl~0.5) +((street:tennis) (defaultField:court~0.5))
哪个会找到匹配项,因为我们可以预期它会找到city:tampa
,state:fl
和street:tennis
(请参阅此Lucene Query Parser文档section以获取另一个示例解释查询解析器的这种行为)。它是否在默认字段中的court
上找到匹配项我不知道,但它确实不需要。
PhraseQuery
是在Lucene查询中将多个术语(单词)串在一起的典型方法(在解析的查询中看起来像street:"tennis court"
)。