Об упругом поиске группы по двум полям, а затем фильтр или порядок - PullRequest
1 голос
/ 26 октября 2019

Существует индекс shareholder, который хочет получить ниже информации

  1. , какой владелец инвестирует в одну и ту же компанию чаще всего

    выберите hld_id, com_id, count (*) из группы акционеров по hld_id, com_id - по количеству (*) desc;

  2. , которое является владельцем инвестиционной компании всего два раза, возможно, дубликаты записей

    выберите hld_id, com_id изгруппа акционеров по hld_id, com_id с count (*) = 2;

Итак, как реализовать вышеуказанные требования с помощью elasticsearch поискового запроса?

1 Ответ

3 голосов
/ 26 октября 2019

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

Отображение:

PUT shareholder
{
  "mappings": {
    "properties": {
      "hld_id": {
        "type": "keyword"
      },
      "com_id":{
        "type": "keyword"
      }
    }
  }
}

Документы:

POST shareholder/_doc/1
{
  "hld_id": "001",
  "com_id": "001"
}

POST shareholder/_doc/2
{
  "hld_id": "001",
  "com_id": "002"
}

POST shareholder/_doc/3
{
  "hld_id": "002",
  "com_id": "001"
}

POST shareholder/_doc/4
{
  "hld_id": "002",
  "com_id": "002"
}

POST shareholder/_doc/5
{
  "hld_id": "002",
  "com_id": "002"               <--- Note I've changed this 
}

Решение 1: Использование агрегации Elasticsearch

Запрос агрегации: 1

Обратите внимание, что я только что использовал Условия запроса , сначала с hld_id, а затем с com_id

POST shareholder/_search
{
  "size": 0,
  "aggs": {
    "share_hoder": {
      "terms": {
        "field": "hld_id"
      },
      "aggs": {
        "com_aggs": {
          "terms": {
            "field": "com_id",
            "order": {
              "_count": "desc"
            }
          }
        }
      }
    }
  }
}

Ниже показано, как выглядит ответ:

Ответ:

 {
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "share_hoder" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "002",
          "doc_count" : 3,
          "com_aggs" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "002",
                "doc_count" : 2                    <---- Count you are looking for
              },
              {
                "key" : "001",
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "001",
          "doc_count" : 2,
          "com_aggs" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "001",
                "doc_count" : 1
              },
              {
                "key" : "002",
                "doc_count" : 1
              }
            ]
          }
        }
      ]
    }
  }
}

Конечно, вы не можете получить представление результата точно так, как вы ищете, из-за того, как работает агрегация Elasticsearch.

Запрос агрегации: 2

Для этого большая часть его совпадает с агрегацией_1, где я использовал два условия запроса , но яМы дополнительно использовали Запрос агрегации кардинальности , чтобы получить счетчик hld_id, а затем я использовал Агрегация селектора блоков , в которой я добавил условия для count()==2

POST shareholder/_search
{
  "size": 0,
  "aggs": {
    "share_holder": {
      "terms": {
        "field": "hld_id",
        "order": {
          "_key": "desc"
        }
      },
      "aggs": {
        "com_aggs": {
          "terms": {
            "field": "com_id"
          },
          "aggs": {
            "count_filter":{
              "bucket_selector": {
                "buckets_path": {
                  "count_path": "_count"
                },
                "script": "params.count_path == 2"
              }
            }
          }
        }
      }
    }
  }
}

Ниже показан ответ.

Ответ:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "share_holder" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "002",
          "doc_count" : 3,
          "com_aggs" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "002",                   
                "doc_count" : 2                     <---- Count == 2
              }
            ]
          }
        },
        {
          "key" : "001",
          "doc_count" : 2,
          "com_aggs" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [ ]
          }
        }
      ]
    }
  }
}

Обратите внимание, что вторая корзина пуста. Я пытаюсь выяснить, могу ли я отфильтровать вышеуказанный запрос, чтобы "key": "001" не появлялся на первом месте.

Решение 2. Использование Elasticsearch SQL:

Если у вас есть версия Kibana для x-pack, вы, вероятно, можете выполнить следующие запросы в стиле SQLish:

Запрос: 1

POST /_sql?format=txt
{
    "query": "SELECT hld_id, com_id, count(*) FROM shareholder GROUP BY hld_id, com_id ORDER BY count(*) desc"
}

Ответ:

    hld_id     |    com_id     |   count(*)    
---------------+---------------+---------------
002            |002            |2              
001            |001            |1              
001            |002            |1              
002            |001            |1              

Запрос 2:

POST /_sql?format=txt
{
    "query": "SELECT hld_id, com_id FROM shareholder GROUP BY hld_id, com_id HAVING count(*) = 2"
}

Ответ:

    hld_id     |    com_id     
---------------+---------------
002            |002            

Решение 3: Использование сценария в терминах агрегирования

Запрос агрегации:

POST shareholder/_search
{
  "size": 0,
  "aggs": {
    "query_groupby_count": {
      "terms": {
        "script": {
          "source": """
              doc['hld_id'].value + ", " + doc['com_id'].value
            """
        }
      }
    },
    "query_groupby_count_equals_2": {
      "terms": {
        "script": {
          "source": """
              doc['hld_id'].value + ", " + doc['com_id'].value
            """
        }
      },
      "aggs": {
        "myaggs": {
          "bucket_selector": {
            "buckets_path": {
              "count": "_count"
            },
            "script": "params.count == 2"
          }

        }
      }
    }

  }
}

Ответ:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "query_groupby_count_equals_2" : {               <---- Group By Query For Count == 2
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "002, 002",
          "doc_count" : 2
        }
      ]
    },
    "query_groupby_count" : {                        <---- Group By Query
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "002, 002",
          "doc_count" : 2
        },
        {
          "key" : "001, 001",
          "doc_count" : 1
        },
        {
          "key" : "001, 002",
          "doc_count" : 1
        },
        {
          "key" : "002, 001",
          "doc_count" : 1
        }
      ]
    }
  }
}

Использование CURL:

Сначала давайте сохраним запрос в файле .txt или .json.

Например, я создал файл с именем query.json, скопировал и вставил только запрос в этот файл.

{
    "query": "SELECT hld_id, com_id, count(*) FROM shareholder GROUP BY hld_id, com_id ORDER BY count(*) desc"
}

Теперь выполните приведенную ниже команду curl, в которой вы будете ссылаться на файл, как показано ниже:

curl -XGET http://localhost:9200/_sql?format=txt -H "Content-Type: application/json" -d @query.json

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...