【问题标题】:ElasticSearch 6.0.1 - SQL DISTINCT clause - NEST C#ElasticSearch 6.0.1 - SQL DISTINCT 子句 - NEST C#
【发布时间】:2020-10-23 15:17:58
【问题描述】:

我需要使用 NEST 从文档中返回所有类别 DISTINCTS(不重复任何内容)。

在 SQL 中是这样的:

SELECT DISTINCT Category  
  FROM Log  
  ORDER BY Category ASC 

在 ElasticSearch 中我是这样做的:

GET log/_search
{
  "size":"0",
  "aggs" : {
  "alias_category" : {
  "terms" : { "field" : "category.keyword" }
  }
  }
}

如何使用 NEST 做到这一点?

public ICollection<string> SelectAllCategoriesDistinct(ElasticClient client)
    {
        var searchResponse = client.Search<LogElasticSearch>(s => s
                                        .Query(q => q
                                            .Terms(t => t
                                                .Field(f => f.Category)
                                            )
                                        )
                                     );
        return (ICollection<string>)searchResponse;
    }

【问题讨论】:

    标签: c# sql elasticsearch nest


    【解决方案1】:

    我找到了一种方法。不是一种优雅的方式,但我在 elastico 网站 (https://discuss.elastic.co/t/c-nest-best-way-of-accessing-properties-of-iaggregate-object/85384/2) 中找到并且我是这样做的:

    public ICollection<string> SelectAllCategoriesDistinct(ElasticClient client)
        {
            var searchResponse = 
                client.Search<LogElasticSearch>(s => s
                    .Size(0)
                    .Aggregations(agg => agg
                        .Terms("categories", t => t
                            .Field("category.keyword")
                        )                  
                    )
                );
           
            var aggregation = searchResponse.Aggregations.Values;
            var listOfCategories = new List<string>();
    
            if (searchResponse.Aggregations.Values.FirstOrDefault().GetType() == typeof(BucketAggregate))
            {
                foreach (IBucket bucket in ((BucketAggregate)aggregation.FirstOrDefault()).Items)
                {
                    if (bucket.GetType() == typeof(KeyedBucket<object>))
                    {
                        var valueKey = ((KeyedBucket<object>)bucket).Key;
                        listOfCategories.Add(valueKey.ToString());
                    }
                } 
            }
    
            return listOfCategories.OrderBy(c => c).ToList();
        }
    

    如果有人知道更好的方法,请帮助我改进,但这样就达到了目标。

    【讨论】:

    • 您可以使用searchResponse.Aggregations.Terms("categories") 获取术语聚合结果(桶等)。搜索响应上的 .Aggregations 属性有一种方便的方法可以从响应中获取每种类型的聚合
    【解决方案2】:

    我会使用composite aggregation 来获取所有条款。与terms aggregation 相比,复合聚合支持分页,因此如果要获取很多 项,则可以发出多个请求

    private static void Main()
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var settings = new ConnectionSettings(pool); 
        var client = new ElasticClient(settings);
        
        var categories = new List<string>();
    
        GetAllCategories(client, categories);
        
        // do something with the categories
        foreach(var category in categories)
            Console.WriteLine(category);
    }
    
    private static void GetAllCategories(IElasticClient client, List<string> categories, CompositeKey after = null)
    {
        // number of terms to fetch in each request
        var size = 10_000;
        
        var response = client.Search<LogElasticSearch>(s => s
            .Size(0)
            .Aggregations(a => a
                .Composite("categories", c => c
                    .After(after)
                    .Size(size)
                    .Sources(so => so
                        .Terms("category", t => t
                            .Field("category.keyword")
                            .Order(SortOrder.Ascending)
                        )
                    )
                )
            )
        );
    
        var compositeAgg = response.Aggregations.Composite("categories");
        var buckets = compositeAgg.Buckets;
    
        foreach (var bucket in buckets)
        {
            if (bucket.Key.TryGetValue("category", out string category))
            {
                categories.Add(category);
            }
        }
    
        // there may be more
        if (buckets.Count == size)
        {
            GetAllCategories(client, categories, compositeAgg.AfterKey);
        }
    }
    

    【讨论】:

    • 你好,拉斯!我忘了指定...我在 6.0.1 版本中使用 elasticsearch。我认为 .Composite 在这个版本中不起作用。
    • @WeslleyRufinodeLima 我认为您只需要使用大尺寸的术语聚合来覆盖所有不同的标签。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 2017-04-12
    • 2018-06-27
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 2021-11-17
    相关资源
    最近更新 更多