首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用NEST构建动态弹性搜索查询

使用NEST构建动态弹性搜索查询
EN

Code Review用户
提问于 2018-06-02 11:25:32
回答 1查看 11.3K关注 0票数 4

我正在使用Elasticsearch v6和NEST搜索我在我的网站上创建的广告。

这是我的文档(我在其中构建Index):

代码语言:javascript
复制
[ElasticsearchType(Name = "document")]
public class Document
{
    public long Id { get; set; }

    [Text(Analyzer = "english")]
    public string Title { get; set; }

    public int Price { get; set; }

    public short AdDurationInDays { get; set; }

    public DateTime AdStartTime { get; set; }

    [Text(Analyzer = "english")]
    public string Description { get; set; }

    [Text(Index = false)]   // Don't want to query this field
    public string MainPhoto { get; set; }

    public int ParentCategoryId { get; set; }
    [Text(Analyzer = "english")]
    public string ParentCategoryName { get; set; }

    public GeoLocation GeoLocation { get; set; }
}

我有一个创建的Elasticsearch客户端,还有一个名为SearchDocuments的方法。我想向这个方法传递一个搜索词(关键字)和一个过滤器列表。搜索文档需要根据搜索项和传入的过滤器构建动态查询。

这是我的搜索方法:

代码语言:javascript
复制
public void SearchDocuments(KeywordMultiMatch Keyword, List<IQueryBuilder> filters)
{
    QueryContainer multiMatchQuery = Keyword.GetQuery();
    QueryContainer filterQuery = null;

    foreach (var filter in filters)
    {
        var query = filter.GetQuery();
        if (query != null)
        {
            filterQuery &= query;
        }
    }

    var res = Client.Search<Document>(new SearchRequest<Document>
    {
        Query = new BoolQuery
        {
            Must = new QueryContainer[] { multiMatchQuery },
            Filter = new QueryContainer[] { filterQuery }
        }
    });
}

为了构建动态搜索查询,我创建了一个名为IQueryBuilder的接口。这个接口有一个名为GetQuery()的方法,它返回一个QueryContainer

代码语言:javascript
复制
public interface IQueryBuilder
{
    QueryContainer GetQuery();
}

现在,我的搜索术语类(关键字)和所有过滤器实现了这个接口,这是KeywordMultiMatch类,它返回一个MultiMatchQuery

代码语言:javascript
复制
public class KeywordMultiMatch : IQueryBuilder
{
    [StringLength(100, MinimumLength = 2)]
    public string keyword { get; set; }

    public QueryContainer GetQuery()
    {
        if (!string.IsNullOrEmpty(keyword))
        {
            var query = new MultiMatchQuery
            {
                Name = "Keyword Multimatch",
                Fields = Fields<Document>(p => p.Title).And<Document>(p => p.Description).And<Document>(p => p.ParentCategoryName).And<Document>(p => p.ParentCategoryName),
                Query = keyword,
                Fuzziness = Fuzziness.EditDistance(1)
            };
            return query;
        }

        return new MatchAllQuery();
    }
}

这是我的LocationFilter课程:

代码语言:javascript
复制
public class LocationFilter : IQueryBuilder
{
    public short Distance { get; set; }

    public GeoLocation GeoLocation { get; set; }

    public QueryContainer GetQuery()
    {
        if (GeoLocation != null && Distance > 0)
        {
            var query = new GeoDistanceQuery
            {
                Name = "Location Filter",
                Field = Field<Document>(p => p.GeoLocation),
                DistanceType = GeoDistanceType.Plane,   // plane is faster but less accurate than arc
                Location = GeoLocation,
                Distance = Distance.ToString() + "km"
            };
            return query;
        }
        return null;
    }
}

这是我的ParentCategoryFilter课程:

代码语言:javascript
复制
public class ParentCategoryFilter : IQueryBuilder
{
    public int ParentCategoryId { get; set; }

    public QueryContainer GetQuery()
    {
        if (ParentCategoryId > 0)
        {
            var query = new TermQuery
            {
                Name = "Parent Category Filter",
                Field = Field<Document>(p => p.ParentCategoryId),
                Value = ParentCategoryId
            };
            return query;
        }
        return null;
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-06-03 12:37:06

抽象单一用途的查询构建器是一个不错的选择。

SearchDocuments的参数应该合并到一个单一的模型中,以简化方法定义。

代码语言:javascript
复制
public class Query {
    public IQueryBuilder Must { get; set; }
    public List<IQueryBuilder> Filters { get; set; }
}

这还应该允许在定义动态搜索查询时具有更大的灵活性,因为现在它并没有与KeywordMultiMatch紧密耦合,在这种情况下,这将是一个实现问题。

代码语言:javascript
复制
public void SearchDocuments(Query args) {
    var filterQuery = args.Filters
        .Select(buider => buider.GetQuery())
        .Where(container => container != null)
        .Aggregate((current, next) => current & next);

    var result = Client.Search<Document>(new SearchRequest<Document> {
        Query = new BoolQuery {
            Must = new QueryContainer[] { args.Must.GetQuery() },
            Filter = new QueryContainer[] { filterQuery }
        }
    });

    //...
}
票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/195689

复制
相关文章

相似问题

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