Elasticsearch — разные значения, а не подсчеты

Я пытаюсь сделать что-то похожее на этот SQL-запрос:

SELECT * FROM table WHERE fileContent LIKE '%keyword%' AND company_id = '1' GROUP BY email

Прочитав сообщения похожие на это, у меня есть следующее:

{
    "query": {
        "bool": {
            "must": [{
                "match": {
                    "fileContent": {
                        "query": "keyword"
                    }
                }
            }],
            "filter": [{
                "terms": {
                    "company_id": [1]
                }
            }]
        }
    },
    "aggs": {
        "group_by_email": {
            "terms": {
                "field": "email",
                "size": 1000
            }
        }
    },
    "size": 0
}

Сопоставления полей:

{
  "cvs" : {
    "mappings" : {
      "application" : {
        "_meta" : {
          "model" : "Acme\\AppBundle\\Entity\\Application"
        },
        "dynamic_date_formats" : [ ],
        "properties" : {
          "email" : {
            "type" : "keyword"
          },
          "fileContent" : {
            "type" : "text"
          },
          "company_id" : {
            "type" : "text"
          }
        }
      }
    }
  }
}

... которые генерируются из Symfony config.yml:

fos_elastica:
    clients:
        default:
            host: "%elastica.host%"
            port: "%elastica.port%"
    indexes:
        cvs:
            client: default
            types:
               application:
                    properties:
                        fileContent: ~
                        email:
                          index: not_analyzed
                        company_id: ~
                    persistence:
                        driver: orm
                        model: Acme\AppBundle\Entity\Application
                        provider: ~
                        finder: ~

Фильтр работает нормально, но я обнаружил, что hits:hits не возвращает ни одного элемента (или все результаты, соответствующие поиску, если я удаляю size:0), а aggregations:group_by_email:buckets имеет количество групп, но не самих записей. Записи, которые были сгруппированы, не возвращаются, и мне нужны именно они.

Я также пробовал использовать FOSElasticBundle с помощью построителя запросов, если это ваш предпочтительный вариант (это работает, но не имеет группировки/агрегации):

$boolQuery = new \Elastica\Query\BoolQuery();

$filterKeywords = new \Elastica\Query\Match();
$filterKeywords->setFieldQuery('fileContent', 'keyword');
$boolQuery->addMust($filterKeywords);

$filterUser = new \Elastica\Query\Terms();
$filterUser->setTerms('company_id', array('1'));
$boolQuery->addFilter($filterUser);

$finder = $this->get('fos_elastica.finder.cvs.application');

Спасибо.


person Egg    schedule 17.05.2017    source источник


Ответы (3)


Для этого вам понадобится top_hits агрегация внутри terms той, которую вы уже используете:

  "aggs": {
    "group_by_email": {
      "terms": {
        "field": "email",
        "size": 1000
      },
      "aggs": {
        "sample_docs": {
          "top_hits": {
            "size": 100
          }
        }
      }
    }
  }
person Andrei Stefan    schedule 17.05.2017
comment
Спасибо за ответ. buckets теперь содержит hits:hits с результатами, но это все равно все записи, соответствующие поиску/фильтру. Глядя на hits:hits:0:_source:email и hits:hits:1:source:email, я вижу один и тот же адрес электронной почты, как будто он не был сгруппирован (электронная почта разделена с помощью @ на два сегмента, но я думаю, что это то, что я могу решить с помощью типов индексов)? - person Egg; 18.05.2017
comment
Каково отображение вашего поля email? - person Andrei Stefan; 18.05.2017
comment
Добавлено к вопросу, чтобы его было легче читать, надеюсь, это то, что вам нужно? - person Egg; 20.05.2017
comment
Ваше поле email имеет тип keyword, что означает, что оно не будет разделено. Поскольку вы видите разделение на @, это означает, что что-то не так с вашим отображением. Проверьте _mapping вашего индекса из самого Elasticsearch (GET /your_index_name/_mapping) и посмотрите, что это за поле email. Я знаю, что вы предоставили сопоставление, но согласно этому сопоставлению ES не должен разбиваться на @. Возможно, вы смотрите не на правильное отображение или не на правильный индекс... - person Andrei Stefan; 23.05.2017
comment
Я добавил index: not_analyzed к отображению, которое предотвращает разделение на @. Я изменил top_hits: {size: 1}, который возвращает только один результат на ведро, это дает результаты, которые я хочу (я опубликую ответ позже, чтобы отразить это). Разбиение на страницы top_hits — это еще одна проблема для другого дня. Спасибо за вашу помощь. - person Egg; 23.05.2017

top_hits:{size:1} похоже, что мне нужно, поигравшись с ответом Андрея. Это вернет одну запись для каждого сегмента в агрегации.

  "aggs": {
    "group_by_email": {
      "terms": {
        "field": "email",
        "size": 1000
      },
      "aggs": {
        "sample_docs": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  }

Ссылка: top_hits< /а>

person Egg    schedule 23.05.2017

top_hits мне тоже помогло. У меня тоже были некоторые проблемы, но в конце концов я понял, как их решить. Итак, вот мое решение:

{
    "query": {
        "nested": {
            "path": "placedOrders",
            "query": {
                "bool": {
                    "must": [
                        {
                            "term": {
                                "placedOrders.ownerId": "0a9fdef0-4508-4f9c-aa8c-b3984e39ad1e"
                            }
                        }
                    ]
                }
            }
        }
    },
    "aggs": {
        "custom_name1": {
            "nested": {
                "path": "placedOrders"
            },
            "aggs": {
                "custom_name2": {
                    "terms": {
                        "field": "placedOrders.propertyId"
                    },
                    "aggs": {
                        "custom_name3": {
                            "top_hits": {
                                "size": 1,
                                "sort": [
                                    {
                                        "placedOrders.propertyId": {
                                            "order": "desc"
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}
person Lukas Zmoginas    schedule 10.03.2020