【问题标题】:ElasticSearch (NEST) Search by NumberElasticSearch (NEST) 按编号搜索
【发布时间】:2018-02-15 01:37:21
【问题描述】:

如果这是一个基本问题,我提前道歉 - 我对 ElasticSearch 非常陌生,需要接受很多内容。

目前,我正在尝试实现一个基本的关键字搜索来搜索所有索引列,但我得到了一些带有特定字段 Year 的奇怪结果。我有一定数量的文件,我知道应该从结果中返回,如果我搜索“2014”,所有文件都会成功返回。如果我只搜索“14”,什么都不会返回,如果我添加一个通配符(例如*14),那么我会得到一个结果,因为它没有使用Year搜索,而是从Description 字段中提取它。

我 100% 肯定这是我在查询结构上做错了,所以有什么提示吗?顺便说一句,如果有人可以提供建议的地方来通过 NEST 了解更多关于 Elastic 的信息,那将非常有帮助。他们的文档有些欠缺,您必须了解如何使用 Elastic 才能理解其中的大部分内容,因为我不知道,所以我只能磕磕绊绊。

这是ElasticListing的结构:

    public long Id { get; set; }

    public string Brand { get; set; }

    public string Manufacturer { get; set; }

    public string ActiveTags { get; set; }

    public string Description { get; set; }

    public int Year { get; set; }

    public string Location { get; set; }

我在 NEST 中使用的搜索结构是这样的,其中 keyword 将是“2014”(无引号):

var response = this.ElasticClient.Search<ElasticListing>(s => s
            .AllTypes()
            .Query(query => query
                .Bool(b => b
                    .Must(must => must
                        .QueryString(qs => qs.Query(keyword))
                    )
                )                   
            )
            .Size(pageSize)
            .Explain()              
        );

【问题讨论】:

    标签: elasticsearch nest


    【解决方案1】:

    您要执行的是对 Elasticsearch 中 Year 字段的 term 查询

    var response = client.Search<ElasticListing>(s => s
        .AllTypes()
        .Query(query => query
            .Term(f => f.Year, 2014)
        )
        .Size(pageSize)
        .Explain()
    );
    

    查看文档的writing queries section

    为了对Year字段进行通配符查询,需要将其索引为keyword data typekeyword不会在索引时分析输入,这可能是我们想要的一个数值被索引为“字符串”)。

    默认情况下,NEST 会将Year 字段序列化为 JSON 中的数字,而 Elasticsearch 会将此映射推断为数字数据类型。即使使用 NEST 的 automapping,NEST 也会推断出 Yearinteger 数据类型映射,以匹配属性的 CLR 类型 Int32。因此,我们需要覆盖这个推断映射以确保 Year 被索引为 keyword 数据类型。

    这是一个完整的例子

    private static void Main()
    {
        var defaultIndex = "listings"; 
        var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
            .DefaultIndex(defaultIndex);
    
        var client = new ElasticClient(settings);
    
        // Make this example re-runnable. You likely want to remove this :)
        if (client.IndexExists(defaultIndex).Exists)
            client.DeleteIndex(defaultIndex);     
    
        client.CreateIndex(defaultIndex, c => c
            .Mappings(m => m
                .Map<ElasticListing>(mm => mm
                    .AutoMap()
                    .Properties(p => p
                        // override the default inferred mapping for Year
                        .Keyword(k => k
                            .Name(n => n.Year) 
                        )
                    )
                )
            )
        );
    
        client.IndexMany(new [] {
            new ElasticListing { Id = 1, Year = 2012 },
            new ElasticListing { Id = 2, Year = 2013 },
            new ElasticListing { Id = 3, Year = 2014 },
            new ElasticListing { Id = 4, Year = 1014 },      
        });
    
        client.Refresh(defaultIndex);
    
        var pageSize = 10;
    
        // returns only document with Id = 3
        var response = client.Search<ElasticListing>(s => s
            .AllTypes()
            .Query(query => query
                .Term(f => f.Year, 2014)
            )
            .Size(pageSize)
            .Explain()
        );
    
        // returns documents with Ids = 3 and 4
        response = client.Search<ElasticListing>(s => s
            .AllTypes()
            .Query(query => query
                .Wildcard(f => f.Year, "*14", rewrite:(MultiTermQueryRewrite)null)
            )
            .Size(pageSize)
            .Explain()
        );
    }
    
    public class ElasticListing
    {
        public long Id { get; set; }
        public string Brand { get; set; }
        public string Manufacturer { get; set; }
        public string ActiveTags { get; set; }
        public string Description { get; set; }
        public int Year { get; set; }
        public string Location { get; set; }
    }
    

    【讨论】:

    • 太棒了 - 谢谢!看起来搜索需要通配符,但除此之外,这完全符合我的需要。
    • 不用担心@RubyHaus :) 请注意不要过度使用通配符和正则表达式查询;对于某些查询,将它们视为类似于在关系数据库中执行表扫描。如果希望在 Year 字段上频繁执行此类查询,请考虑将其创建为 text 数据类型,并对您期望执行的查询类型进行适当的分析。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2021-08-12
    • 2016-10-26
    • 1970-01-01
    相关资源
    最近更新 更多