я использую FOSElasticaBundle с Symfony2 на моем проекте и есть записи и пользовательские таблицы в базе данных MySQL, и каждая запись принадлежит одному пользователю.
Я хочу получить только одну запись на пользователя среди целых записей из базы данных.
Представительство въезда
[
{
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"}
},
{
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"}
},
{
"id": 3,
"name": "Dolar sit amet",
"user": {
"id": 17,
"username": "foo"}
},
]
Ожидаемый результат:
[
{
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"}
},
{
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"}
}
]
Но он возвращает все записи в таблице. Я попытался добавить агрегацию к моему запросу на поиск и ничего не изменилось.
$distinctAgg = new \Elastica\Aggregation\Terms("distinctAgg");
$distinctAgg->setField("user.id");
$distinctAgg->setSize(1);
$query->addAggregation($distinctAgg);
Есть ли способ сделать это через термин фильтр или что-нибудь еще? Любая помощь будет отличной. Спасибо.
Агрегации нелегко понять, когда вы привыкли к группировке MySQL.
Во-первых, является то, что результаты агрегации не возвращаются в hits
, но в aggregations
, Поэтому, когда вы получите результат поиска, вы должны получить такие агрегаты:
$results = $search->search();
$aggregationsResults = $results->getAggregations();
Вторая вещь в том, что агрегаты не вернут вам источник. При агрегировании вашего примера вы будете знать только, что у вас есть 1 пользователь с ID 15 и 2 пользователя с ID 15.
Например. с этим запросом:
{
"query": {
"match_all": {}
},
"aggs": {
"byUser": {
"terms": {
"field": "user.id"}
}
}
}
Результат:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [ ... ]
},
"aggregations": {
"byUser": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 17,
"doc_count": 2
},
{
"key": 15,
"doc_count": 1
}
]
}
}
}
Если вы хотите получить результаты, так же, как вы сделали бы с GROUP BY в MySQL, вы должны использовать top_hits
суб-агрегации:
{
"query": {
"match_all": {}
},
"aggs": {
"byUser": {
"terms": {
"field": "user.id"},
"aggs": {
"results": {
"top_hits": {
"size": 1
}
}
}
}
}
}
Результат:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [ ... ]
},
"aggregations": {
"byUser": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 17,
"doc_count": 2,
"results": {
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "test_stackoverflow",
"_type": "test1",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"name": "Hello world",
"user": {
"id": 17,
"username": "foo"}
}
}
]
}
}
},
{
"key": 15,
"doc_count": 1,
"results": {
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test_stackoverflow",
"_type": "test1",
"_id": "2",
"_score": 1,
"_source": {
"id": 2,
"name": "Lorem ipsum",
"user": {
"id": 15,
"username": "bar"}
}
}
]
}
}
}
]
}
}
}
Больше информации на этой странице: https://www.elastic.co/blog/top-hits-aggregation
Других решений пока нет …