#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 Я думаю, вам нужно просто использовать агрегацию терминов с большим размером, чтобы охватить все отдельные теги.