ElasticSearch 6.0.1 — ОТДЕЛЬНОЕ предложение SQL — ВЛОЖЕННЫЙ C#

#c# #sql #elasticsearch #nest

#c# #sql #elasticsearch #гнездо

Вопрос:

Мне нужно вернуть ТОЛЬКО все различия категорий (без каких-либо повторений) из документа с использованием NEST.

В 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;
    }
  

Ответ №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();
    }
  

Если кто-то знает лучший способ сделать это, помогите мне улучшить, но таким образом он достигает цели.

Комментарии:

1. Вы можете использовать searchResponse.Aggregations.Terms("categories") для получения результатов агрегирования терминов (сегментов и т. Д.). .Aggregations Свойство в ответе поиска имеет удобный метод для получения каждого типа агрегации из ответа

Ответ №2:

Я бы использовал составную агрегацию для извлечения всех терминов. В отличие от агрегации терминов, составная агрегация поддерживает разбивку на страницы, поэтому можно выполнить несколько запросов, если требуется извлечь много терминов

 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);
    }
}
  

Комментарии:

1. Привет, Расс! Я забыл указать … Я использую elasticsearch в версии 6.0.1. Я думаю. Композитный не работает в этой версии.

2. @WeslleyRufinodeLima Я думаю, вам нужно просто использовать агрегацию терминов с большим размером, чтобы охватить все отдельные теги.