如何使用lucene.net使用多个过滤器实现搜索 [英] How to implement search with multiple filters using lucene.net

查看:55
本文介绍了如何使用lucene.net使用多个过滤器实现搜索的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to lucene.net. I want to implement search functionality on a client database. I have the following scenario:

  • 用户将根据当前选择的城市搜索客户.
  • 如果用户要搜索其他城市的客户,则他必须更改城市并再次执行搜索.
  • 要优化搜索结果,我们需要在Areas(多个),Pincode等上提供过滤器.换句话说,我需要与以下sql查询等效的lucene查询:

  • Users will search for clients based on the currently selected city.
  • If the user wants to search for clients in another city, then he has to change the city and perform the search again.
  • To refine the search results we need to provide filters on Areas (multiple), Pincode, etc. In other words, I need the equivalent lucene queries to the following sql queries:

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')

以下是我为向城市提供过滤条件而实现的代码:

Below is the code I've implemented to provide search with city as a filter:

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:

Now I have to provide more filters on Area, Pincode, etc. in which Area is multiple. I tried BooleanQuery like below:

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[]

如果我们对单个区域执行相同的操作,则可以正常工作.

If we perform the same operation with single area then it's working fine.

我已经尝试过使用ChainedFilter,如下所示,这似乎不能满足要求.以下代码在城市和地区上执行或操作.但是要求是在给定城市提供的区域之间执行或"运算.

I've tried with ChainedFilter like below, which doesn't seems to satisfy the requirement. The below code performs or operation on city and areas. But the requirement is to perform OR operation between the areas provided in the given city.

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

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

Can anybody suggest to me how to achieve this in lucene.net? Your help will be appreciated.

推荐答案

您正在寻找

You're looking for the BooleanFilter. Almost any query object has a matching filter object.

查看 TermsFilter (来自 Lucene.Net.Contrib .查询)如果您的索引与 FieldCacheTermsFilter .从后面的文档中; 此过滤器要求该字段仅包含所有文档的单个术语."

Look into TermsFilter (from Lucene.Net.Contrib.Queries) if your indexing doesn't match the requirements of FieldCacheTermsFilter. From the documentation of the later; "this filter requires that the field contains only a single term for all documents".

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;

这篇关于如何使用lucene.net使用多个过滤器实现搜索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆