Получение уникальных результатов с помощью поиска в соответствии с полем

я использую 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);

Есть ли способ сделать это через термин фильтр или что-нибудь еще? Любая помощь будет отличной. Спасибо.

1

Решение

Агрегации нелегко понять, когда вы привыкли к группировке 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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]