【问题标题】:How to implement search with multiple filters using lucene.net如何使用 lucene.net 实现具有多个过滤器的搜索
【发布时间】:2014-05-26 09:59:43
【问题描述】:

我是 lucene.net 的新手。我想在客户端数据库上实现搜索功能。我有以下情况:

  • 用户将根据当前选择的城市搜索客户。
  • 如果用户想在另一个城市搜索客户,那么他必须更改城市并再次执行搜索。
  • 要优化搜索结果,我们需要提供区域(多个)、Pincode 等过滤器。换句话说,我需要对以下 sql 查询等效的 lucene 查询:

    SELECT * FROM CLIENTS
         WHERE CITY = N'City1'
         AND (Area like N'%area1%' OR Area like N'%area2%')
    
    SELECT * FROM CILENTS
        WHERE CITY IN ('MUMBAI', 'DELHI')
        AND CLIENTTYPE IN ('GOLD', 'SILVER')
    

下面是我实现的代码,以提供城市作为过滤器的搜索:

private static IEnumerable<ClientSearchIndexItemDto> _search(string searchQuery, string city, string searchField = "")
{
    // validation
    if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", "")))
        return new List<ClientSearchIndexItemDto>();

    // set up Lucene searcher
    using (var searcher = new IndexSearcher(_directory, false))
    {
        var hits_limit = 1000;
        var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);

        // search by single field
        if (!string.IsNullOrEmpty(searchField))
        {
            var parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, searchField, analyzer);
            var query = parseQuery(searchQuery, parser);
            var hits = searcher.Search(query, hits_limit).ScoreDocs;
            var results = _mapLuceneToDataList(hits, searcher);
            analyzer.Close();
            searcher.Dispose();
            return results;
        }
        else // search by multiple fields (ordered by RELEVANCE)
        {
            var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, new[]
            {
                "ClientId",
                "ClientName",
                "ClientTypeNames",
                "CountryName",
                "StateName",
                "DistrictName",
                "City",
                "Area",
                "Street",
                "Pincode",
                "ContactNumber",
                "DateModified"
            }, analyzer);
            var query = parseQuery(searchQuery, parser);
            var f = new FieldCacheTermsFilter("City",new[] { city });
            var hits = searcher.Search(query, f, hits_limit, Sort.RELEVANCE).ScoreDocs;
            var results = _mapLuceneToDataList(hits, searcher);
            analyzer.Close();
            searcher.Dispose();
            return results;
        }
    }
}

现在我必须提供更多关于 Area、Pincode 等的过滤器,其中 Area 是多个。我尝试了如下的 BooleanQuery:

var cityFilter = new TermQuery(new Term("City", city));
var areasFilter = new FieldCacheTermsFilter("Area",areas); -- where type of areas is string[]

BooleanQuery filterQuery = new BooleanQuery();
filterQuery.Add(cityFilter, Occur.MUST);
filterQuery.Add(areasFilter, Occur.MUST); -- here filterQuery.Add not have an overloaded method which accepts string[]

如果我们对单个区域执行相同的操作,那么它工作正常。

我已经尝试过如下所示的 ChainedFilter,它似乎不能满足要求。以下代码对城市和地区执行或操作。但要求是在给定城市提供的区域之间执行 OR 操作。

var f = new ChainedFilter(new Filter[] { cityFilter, areasFilter });

有人可以向我建议如何在 lucene.net 中实现这一点吗?您的帮助将不胜感激。

【问题讨论】:

    标签: lucene.net


    【解决方案1】:

    您正在寻找BooleanFilter。几乎所有查询对象都有匹配的过滤器对象。

    如果您的索引不符合FieldCacheTermsFilter 的要求,请查看TermsFilter(来自Lucene.Net.Contrib.Queries)。从后来的文档中; “此过滤器要求该字段仅包含所有文档的单个术语”。

    var cityFilter = new FieldCacheTermsFilter("CITY", new[] {"MUMBAI", "DELHI"});
    var clientTypeFilter = new FieldCacheTermsFilter("CLIENTTYPE", new [] { "GOLD", "SILVER" });
    
    var areaFilter = new TermsFilter();
    areaFilter.AddTerm(new Term("Area", "area1"));
    areaFilter.AddTerm(new Term("Area", "area2"));
    
    var filter = new BooleanFilter();
    filter.Add(new FilterClause(cityFilter, Occur.MUST));
    filter.Add(new FilterClause(clientTypeFilter, Occur.MUST));
    filter.Add(new FilterClause(areaFilter, Occur.MUST));
    
    IndexSearcher searcher = null; // TODO.
    Query query = null; // TODO.
    Int32 hits_limit = 0; // TODO.
    var hits = searcher.Search(query, filter, hits_limit, Sort.RELEVANCE).ScoreDocs;
    

    【讨论】:

      【解决方案2】:

      您正在寻找的是嵌套布尔查询,以便您有一个或(在您的城市),但整个组(匹配或)本身匹配为一个和

      filter1 AND filter2 AND filter3 AND (filtercity1 OR filtercity2 OR filtercity3)
      

      这里已经很好地描述了如何做到这一点:

      How to create nested boolean query with lucene API (a AND (b OR c))?

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 2019-07-03
        • 2010-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-05
        • 2017-01-30
        • 2019-07-12
        相关资源
        最近更新 更多