読者です 読者をやめる 読者になる 読者になる

ElasticsearchのSearch APIを試す

ElasticsearchでSearch APIを使ってみたメモです。

前回ElasticsearchとKibanaをインストールしたので、Search APIを使ってみました。

公式のサンプルを試しただけなので、下記の公式ドキュメントを見たほうが早いです。
www.elastic.co

Consoleで使ってみます。

サンプルデータ登録

サンプルデータセットを下記からダウンロードします。
銀行の口座のダミーデータになってます。
https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json

データの登録ですが、curlだと下記のように--data-binaryでファイル名を指定すれば登録できますが、
Consoleからだと出来ないようです(たぶん)。

curl -XPOST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"

なので、データをコピーしてそのままConsoleに全部貼り付けて登録します。
bulk APIを使用して登録します。bulk APIを使用すると一度のリクエストで複数の登録/削除が出来ます。

bankインデックスのaccountタイプに登録。

POST /bank/account/_bulk?pretty&refresh 
{
  "index": {
    "_id": "1"
  }
}
{
  "account_number": 1,
  "balance": 39225,
  "firstname": "Amber",
  "lastname": "Duke",
  "age": 32,
  "gender": "M",
  "address": "880 Holmes Lane",
  "employer": "Pyrami",
  "email": "amberduke@pyrami.com",
  "city": "Brogan",
  "state": "IL"
}
{
  "index": {
    "_id": "6"
  }
}
{
  "account_number": 6,
  "balance": 5686,
  "firstname": "Hattie",
  "lastname": "Bond",
  "age": 36,
  "gender": "M",
  "address": "671 Bristol Street",
  "employer": "Netagy",
  "email": "hattiebond@netagy.com",
  "city": "Dante",
  "state": "TN"
}
       :
       :
       :

レスポンス。

{
  "took": 1291,
  "errors": false,
  "items": [
    {
      "index": {
        "_index": "bank",
        "_type": "account",
        "_id": "1",
        "_version": 1,
        "result": "created",
        "forced_refresh": true,
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "created": true,
        "status": 201
      }
    },
    {
      "index": {
        "_index": "bank",
        "_type": "account",
        "_id": "6",
        "_version": 1,
        "result": "created",
        "forced_refresh": true,
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "created": true,
        "status": 201
      }
    },
       :
       :
       :

cat APIを使用して、index情報を確認。

GET _cat/indices?v

レスポンス。docs.countで1000件登録されたことがわかります。

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   bank    CEbEH4CPTX-fANp3RtD0Bg   5   1       1000            0    648.9kb        648.9kb
yellow open   .kibana J4PlELzCRu-7_kI76iDCsQ   1   1          1            0      3.2kb          3.2kb

Search API

Search APIを実行する方法は2通りあって、REST request URIにパラメータを指定する方法と、
REST request BODYにjsonを指定する方法があります。

リクエストパラメータでbankインデックスを全件取得してみます。

Search APIは_searchがエンドポイントになってます。
各パラメータは下記の通り。
・q=*:全ドキュメントを対象
・sort=account_number:asc:account_numberの昇順でソート
・pretty:整形されたjsonのレスポンスを要求

GET /bank/_search?q=*&sort=account_number:asc&pretty

レスポンス。
・took:検索の処理時間(msec)
・timed_out:検索のタイムアウト有無。false⇒タイムアウトしてない
・_shards:検索されたシャードの数
・hits:検索結果
・hits.total:検索条件に一致する全ドキュメント数
・hits.hits:検索結果の配列(デフォルトは10ドキュメント)
・sort:ソートの順番

{
  "took": 16,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": null,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "0",
        "_score": null,
        "_source": {
          "account_number": 0,
          "balance": 16623,
          "firstname": "Bradshaw",
          "lastname": "Mckenzie",
          "age": 29,
          "gender": "F",
          "address": "244 Columbus Place",
          "employer": "Euron",
          "email": "bradshawmckenzie@euron.com",
          "city": "Hobucken",
          "state": "CO"
        },
        "sort": [
          0
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "1",
        "_score": null,
        "_source": {
          "account_number": 1,
          "balance": 39225,
          "firstname": "Amber",
          "lastname": "Duke",
          "age": 32,
          "gender": "M",
          "address": "880 Holmes Lane",
          "employer": "Pyrami",
          "email": "amberduke@pyrami.com",
          "city": "Brogan",
          "state": "IL"
        },
        "sort": [
          1
        ]
      },
       :
       :
       :
      {
        "_index": "bank",
        "_type": "account",
        "_id": "9",
        "_score": null,
        "_source": {
          "account_number": 9,
          "balance": 24776,
          "firstname": "Opal",
          "lastname": "Meadows",
          "age": 39,
          "gender": "M",
          "address": "963 Neptune Avenue",
          "employer": "Cedward",
          "email": "opalmeadows@cedward.com",
          "city": "Olney",
          "state": "OH"
        },
        "sort": [
          9
        ]
      }
    ]
  }
}

同じ検索をリクエストボディで実行してみます。
q=*の代わりに下記のjsonを指定します。
・"match_all":{}:すべてのドキュメントを対象。
・"sort":account_numberの昇順でソート

GET /bank/_search?pretty
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}

レスポンス。

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": null,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "0",
        "_score": null,
        "_source": {
          "account_number": 0,
          "balance": 16623,
          "firstname": "Bradshaw",
          "lastname": "Mckenzie",
          "age": 29,
          "gender": "F",
          "address": "244 Columbus Place",
          "employer": "Euron",
          "email": "bradshawmckenzie@euron.com",
          "city": "Hobucken",
          "state": "CO"
        },
        "sort": [
          0
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "1",
        "_score": null,
        "_source": {
          "account_number": 1,
          "balance": 39225,
          "firstname": "Amber",
          "lastname": "Duke",
          "age": 32,
          "gender": "M",
          "address": "880 Holmes Lane",
          "employer": "Pyrami",
          "email": "amberduke@pyrami.com",
          "city": "Brogan",
          "state": "IL"
        },
        "sort": [
          1
        ]
      },
       :
       :
       :
      {
        "_index": "bank",
        "_type": "account",
        "_id": "9",
        "_score": null,
        "_source": {
          "account_number": 9,
          "balance": 24776,
          "firstname": "Opal",
          "lastname": "Meadows",
          "age": 39,
          "gender": "M",
          "address": "963 Neptune Avenue",
          "employer": "Cedward",
          "email": "opalmeadows@cedward.com",
          "city": "Olney",
          "state": "OH"
        },
        "sort": [
          9
        ]
      }
    ]
  }
}

match_all

match_allですべてのドキュメントを対象に検索します。

GET /bank/_search?pretty
{
  "query": { "match_all": {} }
}

レスポンス

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "25",
        "_score": 1,
        "_source": {
          "account_number": 25,
          "balance": 40540,
          "firstname": "Virginia",
          "lastname": "Ayala",
          "age": 39,
          "gender": "F",
          "address": "171 Putnam Avenue",
          "employer": "Filodyne",
          "email": "virginiaayala@filodyne.com",
          "city": "Nicholson",
          "state": "PA"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "44",
        "_score": 1,
        "_source": {
          "account_number": 44,
          "balance": 34487,
          "firstname": "Aurelia",
          "lastname": "Harding",
          "age": 37,
          "gender": "M",
          "address": "502 Baycliff Terrace",
          "employer": "Orbalix",
          "email": "aureliaharding@orbalix.com",
          "city": "Yardville",
          "state": "DE"
        }
      },
       :
       :
       :

size

sizeで結果のドキュメント数を指定。デフォルトは10です。

GET /bank/_search?pretty
{
  "query": { "match_all": {} },
  "size": 1
}

レスポンス。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "25",
        "_score": 1,
        "_source": {
          "account_number": 25,
          "balance": 40540,
          "firstname": "Virginia",
          "lastname": "Ayala",
          "age": 39,
          "gender": "F",
          "address": "171 Putnam Avenue",
          "employer": "Filodyne",
          "email": "virginiaayala@filodyne.com",
          "city": "Nicholson",
          "state": "PA"
        }
      }
    ]
  }
}

from

fromで開始するドキュメントのインデックスを指定します。デフォルトは0。
sizeを指定すると、fromから始まりsize件のドキュメントを返します。

GET /bank/_search?pretty
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}

レスポンス。

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "227",
        "_score": 1,
        "_source": {
          "account_number": 227,
          "balance": 19780,
          "firstname": "Coleman",
          "lastname": "Berg",
          "age": 22,
          "gender": "M",
          "address": "776 Little Street",
          "employer": "Exoteric",
          "email": "colemanberg@exoteric.com",
          "city": "Eagleville",
          "state": "WV"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "253",
        "_score": 1,
        "_source": {
          "account_number": 253,
          "balance": 20240,
          "firstname": "Melissa",
          "lastname": "Gould",
          "age": 31,
          "gender": "M",
          "address": "440 Fuller Place",
          "employer": "Buzzopia",
          "email": "melissagould@buzzopia.com",
          "city": "Lumberton",
          "state": "MD"
        }
      },
       :
       :
       :

sort, order

sortでソートするフィールドを指定し、orderでソート順を指定します。
下記では、balanceフィールドの降順にソートします。

GET /bank/_search?pretty
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}

レスポンス。

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": null,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "248",
        "_score": null,
        "_source": {
          "account_number": 248,
          "balance": 49989,
          "firstname": "West",
          "lastname": "England",
          "age": 36,
          "gender": "M",
          "address": "717 Hendrickson Place",
          "employer": "Obliq",
          "email": "westengland@obliq.com",
          "city": "Maury",
          "state": "WA"
        },
        "sort": [
          49989
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "854",
        "_score": null,
        "_source": {
          "account_number": 854,
          "balance": 49795,
          "firstname": "Jimenez",
          "lastname": "Barry",
          "age": 25,
          "gender": "F",
          "address": "603 Cooper Street",
          "employer": "Verton",
          "email": "jimenezbarry@verton.com",
          "city": "Moscow",
          "state": "AL"
        },
        "sort": [
          49795
        ]
      },
       :
       :
       :

_source

検索結果はすべてのフィールドを返します。
一部のフィールドのみ返してほしい場合は_sourceフィールドを指定します。
SQLでいう、SELECT FROMで指定するカラムに似ています。
下記の場合、account_numberとbalanceフィールドのみ返すように指定しています。

GET /bank/_search?pretty
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

レスポンス。

{
  "took": 22,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "25",
        "_score": 1,
        "_source": {
          "account_number": 25,
          "balance": 40540
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "44",
        "_score": 1,
        "_source": {
          "account_number": 44,
          "balance": 34487
        }
      },
       :
       :
       :

match

matchでフィールドの検索を指定することが出来ます。
下記の場合、account_numberが20のドキュメントを返します。

GET /bank/_search?pretty
{
  "query": { "match": { "account_number": 20 } }
}

レスポンス。

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "20",
        "_score": 1,
        "_source": {
          "account_number": 20,
          "balance": 16418,
          "firstname": "Elinor",
          "lastname": "Ratliff",
          "age": 36,
          "gender": "M",
          "address": "282 Kings Place",
          "employer": "Scentric",
          "email": "elinorratliff@scentric.com",
          "city": "Ribera",
          "state": "WA"
        }
      }
    ]
  }
}

下記の場合、addressにmillを含むドキュメントを返します(部分一致)。

GET /bank/_search?pretty
{
  "query": { "match": { "address": "mill" } }
}

レスポンス。

{
  "took": 8,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": 4.3100996,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "472",
        "_score": 4.3100996,
        "_source": {
          "account_number": 472,
          "balance": 25571,
          "firstname": "Lee",
          "lastname": "Long",
          "age": 32,
          "gender": "F",
          "address": "288 Mill Street",
          "employer": "Comverges",
          "email": "leelong@comverges.com",
          "city": "Movico",
          "state": "MT"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "136",
        "_score": 4.2662063,
        "_source": {
          "account_number": 136,
          "balance": 45801,
          "firstname": "Winnie",
          "lastname": "Holland",
          "age": 38,
          "gender": "M",
          "address": "198 Mill Lane",
          "employer": "Neteria",
          "email": "winnieholland@neteria.com",
          "city": "Urie",
          "state": "IL"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "970",
        "_score": 3.861861,
        "_source": {
          "account_number": 970,
          "balance": 19648,
          "firstname": "Forbes",
          "lastname": "Wallace",
          "age": 28,
          "gender": "M",
          "address": "990 Mill Road",
          "employer": "Pheast",
          "email": "forbeswallace@pheast.com",
          "city": "Lopezo",
          "state": "AK"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "345",
        "_score": 3.861861,
        "_source": {
          "account_number": 345,
          "balance": 9812,
          "firstname": "Parker",
          "lastname": "Hines",
          "age": 38,
          "gender": "M",
          "address": "715 Mill Avenue",
          "employer": "Baluba",
          "email": "parkerhines@baluba.com",
          "city": "Blackgum",
          "state": "KY"
        }
      }
    ]
  }
}

下記の例ではaddressにmillまたはlaneを含むドキュメントを返します。

GET /bank/_search?pretty
{
  "query": { "match": { "address": "mill lane" } }
}

レスポンス

{
  "took": 15,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 19,
    "max_score": 7.3900023,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "136",
        "_score": 7.3900023,
        "_source": {
          "account_number": 136,
          "balance": 45801,
          "firstname": "Winnie",
          "lastname": "Holland",
          "age": 38,
          "gender": "M",
          "address": "198 Mill Lane",
          "employer": "Neteria",
          "email": "winnieholland@neteria.com",
          "city": "Urie",
          "state": "IL"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "472",
        "_score": 4.3100996,
        "_source": {
          "account_number": 472,
          "balance": 25571,
          "firstname": "Lee",
          "lastname": "Long",
          "age": 32,
          "gender": "F",
          "address": "288 Mill Street",
          "employer": "Comverges",
          "email": "leelong@comverges.com",
          "city": "Movico",
          "state": "MT"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "556",
        "_score": 3.9074605,
        "_source": {
          "account_number": 556,
          "balance": 36420,
          "firstname": "Collier",
          "lastname": "Odonnell",
          "age": 35,
          "gender": "M",
          "address": "591 Nolans Lane",
          "employer": "Sultraxin",
          "email": "collierodonnell@sultraxin.com",
          "city": "Fulford",
          "state": "MD"
        }
      },
       :
       :
       :

match_phrase

match_phraseを使用すると、addressにmillとlane両方含むドキュメントを検索できます。

GET /bank/_search?pretty
{
  "query": { "match_phrase": { "address": "mill lane" } }
}

レスポンス

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 7.3900023,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "136",
        "_score": 7.3900023,
        "_source": {
          "account_number": 136,
          "balance": 45801,
          "firstname": "Winnie",
          "lastname": "Holland",
          "age": 38,
          "gender": "M",
          "address": "198 Mill Lane",
          "employer": "Neteria",
          "email": "winnieholland@neteria.com",
          "city": "Urie",
          "state": "IL"
        }
      }
    ]
  }
}

bool query

bool queryを使用すると、各bool句の結果のbool値を組み合わせてクエリを実行できます。

must

下記の例では2つのmatchクエリを作成し、must句でどちらの結果もtrueとなるドキュメントを検索します。
結果としてaddressにmillとlane両方含むドキュメントが返ります。

GET /bank/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

レスポンス

{
  "took": 8,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 7.3900023,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "136",
        "_score": 7.3900023,
        "_source": {
          "account_number": 136,
          "balance": 45801,
          "firstname": "Winnie",
          "lastname": "Holland",
          "age": 38,
          "gender": "M",
          "address": "198 Mill Lane",
          "employer": "Neteria",
          "email": "winnieholland@neteria.com",
          "city": "Urie",
          "state": "IL"
        }
      }
    ]
  }
}
should

下記の例では2つのmatchクエリを作成し、should句でいずれかの結果がtrueとなるドキュメントを検索します。
(一致するshould句の最小数はminimum_should_matchで指定可能)
結果としてaddressにmillまたはlaneを含むドキュメントが返ります。

GET /bank/_search?pretty
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

レスポンス

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 19,
    "max_score": 7.3900023,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "136",
        "_score": 7.3900023,
        "_source": {
          "account_number": 136,
          "balance": 45801,
          "firstname": "Winnie",
          "lastname": "Holland",
          "age": 38,
          "gender": "M",
          "address": "198 Mill Lane",
          "employer": "Neteria",
          "email": "winnieholland@neteria.com",
          "city": "Urie",
          "state": "IL"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "472",
        "_score": 4.3100996,
        "_source": {
          "account_number": 472,
          "balance": 25571,
          "firstname": "Lee",
          "lastname": "Long",
          "age": 32,
          "gender": "F",
          "address": "288 Mill Street",
          "employer": "Comverges",
          "email": "leelong@comverges.com",
          "city": "Movico",
          "state": "MT"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "556",
        "_score": 3.9074605,
        "_source": {
          "account_number": 556,
          "balance": 36420,
          "firstname": "Collier",
          "lastname": "Odonnell",
          "age": 35,
          "gender": "M",
          "address": "591 Nolans Lane",
          "employer": "Sultraxin",
          "email": "collierodonnell@sultraxin.com",
          "city": "Fulford",
          "state": "MD"
        }
      },
       :
       :
       :
must_not

下記の例では2つのmatchクエリを作成し、must_not句で結果がtrueとなるドキュメントを除外します。
結果としてaddressにmillとlaneのいずれも含まないドキュメントが返ります。

GET /bank/_search?pretty
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

レスポンス

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 981,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "25",
        "_score": 1,
        "_source": {
          "account_number": 25,
          "balance": 40540,
          "firstname": "Virginia",
          "lastname": "Ayala",
          "age": 39,
          "gender": "F",
          "address": "171 Putnam Avenue",
          "employer": "Filodyne",
          "email": "virginiaayala@filodyne.com",
          "city": "Nicholson",
          "state": "PA"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "44",
        "_score": 1,
        "_source": {
          "account_number": 44,
          "balance": 34487,
          "firstname": "Aurelia",
          "lastname": "Harding",
          "age": 37,
          "gender": "M",
          "address": "502 Baycliff Terrace",
          "employer": "Orbalix",
          "email": "aureliaharding@orbalix.com",
          "city": "Yardville",
          "state": "DE"
        }
      },
       :
       :
       :

bool queryではmust、should、must_notはそれぞれ組み合わせることが出来ます。
下記の例では、年齢が40歳でID(アイダホ州)でないドキュメントが返ります。

GET /bank/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}

レスポンス

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 43,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "948",
        "_score": 1,
        "_source": {
          "account_number": 948,
          "balance": 37074,
          "firstname": "Sargent",
          "lastname": "Powers",
          "age": 40,
          "gender": "M",
          "address": "532 Fiske Place",
          "employer": "Accuprint",
          "email": "sargentpowers@accuprint.com",
          "city": "Umapine",
          "state": "AK"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "40",
        "_score": 1,
        "_source": {
          "account_number": 40,
          "balance": 33882,
          "firstname": "Pace",
          "lastname": "Molina",
          "age": 40,
          "gender": "M",
          "address": "263 Ovington Court",
          "employer": "Cytrak",
          "email": "pacemolina@cytrak.com",
          "city": "Silkworth",
          "state": "OR"
        }
      },
       :
       :
       :

range

filter句でフィルタリングを指定でき、range句で範囲を指定できます。
下記の例では残高が20000〜30000の口座を検索します。

GET /bank/_search?pretty
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}

レスポンス

{
  "took": 34,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 217,
    "max_score": 1,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "253",
        "_score": 1,
        "_source": {
          "account_number": 253,
          "balance": 20240,
          "firstname": "Melissa",
          "lastname": "Gould",
          "age": 31,
          "gender": "M",
          "address": "440 Fuller Place",
          "employer": "Buzzopia",
          "email": "melissagould@buzzopia.com",
          "city": "Lumberton",
          "state": "MD"
        }
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "400",
        "_score": 1,
        "_source": {
          "account_number": 400,
          "balance": 20685,
          "firstname": "Kane",
          "lastname": "King",
          "age": 21,
          "gender": "F",
          "address": "405 Cornelia Street",
          "employer": "Tri@Tribalog",
          "email": "kaneking@tri@tribalog.com",
          "city": "Gulf",
          "state": "VT"
        }
      },
       :
       :
       :

aggs

aggregations(aggs)を使用して、結果に対して様々な集計が出来ます。

group_by_stateという集計の名前を定義します。
termsで指定されたいずれかの値を含む文書を検索します。
下記の例ではstateでグループ化して、件数の降順でソートします。

GET /bank/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}

レスポンス

{
  "took": 49,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "group_by_state": {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets": [
        {
          "key": "ID",
          "doc_count": 27
        },
        {
          "key": "TX",
          "doc_count": 27
        },
        {
          "key": "AL",
          "doc_count": 25
        },
        {
          "key": "MD",
          "doc_count": 25
        },
        {
          "key": "TN",
          "doc_count": 23
        },
        {
          "key": "MA",
          "doc_count": 21
        },
       :
       :
       :

SQLだと下記をシミュレートした感じです。

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC

さらに集計した結果からstate別の平均残高で集計する場合の例。
aggsはネストすることができます。

GET /bank/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

レスポンス

{
  "took": 23,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "group_by_state": {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets": [
        {
          "key": "ID",
          "doc_count": 27,
          "average_balance": {
            "value": 24368.777777777777
          }
        },
        {
          "key": "TX",
          "doc_count": 27,
          "average_balance": {
            "value": 27462.925925925927
          }
        },
        {
          "key": "AL",
          "doc_count": 25,
          "average_balance": {
            "value": 25739.56
          }
        },
        {
          "key": "MD",
          "doc_count": 25,
          "average_balance": {
            "value": 24963.52
          }
        },
       :
       :
       :

先程の例を平均残高の降順でソートする場合。

GET /bank/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

レスポンス

{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "group_by_state": {
      "doc_count_error_upper_bound": -1,
      "sum_other_doc_count": 918,
      "buckets": [
        {
          "key": "AL",
          "doc_count": 6,
          "average_balance": {
            "value": 41418.166666666664
          }
        },
        {
          "key": "SC",
          "doc_count": 1,
          "average_balance": {
            "value": 40019
          }
        },
        {
          "key": "AZ",
          "doc_count": 10,
          "average_balance": {
            "value": 36847.4
          }
        },
        {
          "key": "VA",
          "doc_count": 13,
          "average_balance": {
            "value": 35418.846153846156
          }
        },
       :
       :
       :

さらに、年齢層別(20歳~29歳、30歳~39歳、40歳~49歳)にグループ化してから性別でグループ化し、
年齢層別の性別ごとの平均残高を取得する場合。

GET /bank/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

レスポンス

{
  "took": 36,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "group_by_age": {
      "buckets": [
        {
          "key": "20.0-30.0",
          "from": 20,
          "to": 30,
          "doc_count": 451,
          "group_by_gender": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "M",
                "doc_count": 232,
                "average_balance": {
                  "value": 27374.05172413793
                }
              },
              {
                "key": "F",
                "doc_count": 219,
                "average_balance": {
                  "value": 25341.260273972603
                }
              }
            ]
          }
        },
        {
          "key": "30.0-40.0",
          "from": 30,
          "to": 40,
          "doc_count": 504,
          "group_by_gender": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "F",
                "doc_count": 253,
                "average_balance": {
                  "value": 25670.869565217392
                }
              },
              {
                "key": "M",
                "doc_count": 251,
                "average_balance": {
                  "value": 24288.239043824702
                }
              }
            ]
          }
        },
        {
          "key": "40.0-50.0",
          "from": 40,
          "to": 50,
          "doc_count": 45,
          "group_by_gender": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "M",
                "doc_count": 24,
                "average_balance": {
                  "value": 26474.958333333332
                }
              },
              {
                "key": "F",
                "doc_count": 21,
                "average_balance": {
                  "value": 27992.571428571428
                }
              }
            ]
          }
        }
      ]
    }
  }
}

公式のドキュメントが順序を追って学べる形になっていたので分かりやすかったです。
終わり。