レストランデータセットを使ったElasticsearchチュートリアルを参考にしながらクエリをいろいろ試してみる



# 環境
* Elasticsearch: 2.3.5
* kibana: 4.5.1 (マップがエラーになる件のものは4.5.4を入れて試している)

すべてのクエリはSenseのプラグインを入れて発行しています。
なお、検索結果は適宜省略しています。

# 事前準備
* [Elasticsearchチュートリアル](http://code46.hatenablog.com/entry/2014/01/21/115620)を見てから、自分でレストランデータをElasticsearchに入れる。なおデータセットのフィールドの詳しい説明は[ここ](http://blog.livedoor.jp/techblog/archives/65836960.html)にある
* http://qiita.com/wapa5pow/items/31e966b9d251e7fd76ec でデータを入れる手順を示した


# はじめに

すべてを条件なしで検索してみます。

クエリ

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "match_all": {}
  }
}
```

結果(最初なので、検索結果に解説を付け加えます.

```json
{
  "took": 2,  //検索結果を実行するためかかった時間[msec]
  "timed_out": false,  //検索がタイムアウトしたかどうか
  "_shards": {  //いくつシャードが検索に使われたか
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 214241,  //検索結果の合計数
    "max_score": 1, 
    "hits": [
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "19222",
        "_score": 1,
        "_source": {
          "description": "東京メトロ日比谷線広尾駅から徒歩7分",
          "access_count": "1813",
          "closed": "0",
          "address": "渋谷区広尾５-８-１４東京建物広尾ビルB1",
          "pref_id": "13",
          "open_lunch": "1",
          "special_count": "0",
          "modified_on": "2011-04-20 22:00:07",
          "name_kana": "あさの",
          "purpose": null,
          "alphabet": null,
          "station_id1": "2934",
          "property": null,
          "name": "浅野",
          "category_id1": "302",
          "station_time1": "6",
          "station_distance2": "1403",
          "fan_count": "0",
          "category_id5": "0",
          "open_late": "0",
          "created_on": "2005-02-13 22:36:40",
          "station_distance1": "482",
          "category_id4": "0",
          "zip": null,
          "area_id": "7",
          "id": "19222",
          "north_latitude": "35.38.42.216",
          "category_id3": "0",
          "station_distance3": "1707",
          "open_morning": "0",
          "photo_count": "0",
          "station_time2": "18",
          "menu_count": "0",
          "category_id2": "332",
          "station_time3": "21",
          "station_id2": "1673",
          "east_longitude": "139.43.28.610",
          "station_id3": "8921"
        }
      },
...
```

また、特定のフィールドをページングを指定して検索するには以下のようにします。

```json
GET ldgourmet/restaurant/_search
{
  "from": 9,
  "size": 3,
  "fields": ["name", "description"],
  "query": {
    "term": { "name": "居酒屋" }
  }
}
```

```json
{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 4410,
    "max_score": 2.787416,
    "hits": [
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "335330",
        "_score": 2.787416,
        "fields": {
          "name": [
            "居酒屋　味平"
          ]
        }
      },
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "310316",
        "_score": 2.787416,
        "fields": {
          "name": [
            "居酒屋 遊味"
          ],
          "description": [
            "阪神タイガースファンが集まる店  東武線蒲生駅西口から徒歩１分"
          ]
        }
      },
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "475390",
        "_score": 2.787416,
        "fields": {
          "name": [
            "居酒屋　和味"
          ]
        }
      }
    ]
  }
}
```

また、特定のドキュメントを消したい場合は以下のようにします。

```
DELETE ldgourmet/restaurant/19222
```

# 基本的なクエリ

## [term](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html), [terms](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html)

termクエリは先ほど出てきましたが、termsクエリは、複数の語句を指定のフィールドにマッチしているか確かめる。以下の場合だと、居酒屋もしくはあゆにマッチした語句をもつものが検索結果として取得される。結果はスコアの高い順にならべられるので、「居酒屋　あゆ」がトップにくる。

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "terms": { 
      "name": ["居酒屋", "あゆ"]
    }
  }
}
```

## [match](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-match-query.html), [multi match](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-multi-match-query.html)

multi matchは複数のフィールドのマッチする。

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "match" : {
      "name" : "居酒屋 あゆ"  
    }
  }
}

# 語句の条件を指定. andだとすべての語句を含まなければいけない
GET ldgourmet/restaurant/_search
{
  "query": {
    "match" : {
      "name" : {
        "query": "居酒屋 あゆ",
        "operator": "and"
      }
    }
  }
}

# あいまい検索
GET ldgourmet/restaurant/_search
{
  "query": {
    "match" : {
      "name" : {
        "query": "居酒屋 あゆ",
        "operator": "and",
        "fuzziness": 2,
        "prefix_length" : 1
      }
    }
  }
}

# 複数のフィールドにマッチしたものを探す。ただし、nameの重みを2倍にする
GET ldgourmet/restaurant/_search
{
  "query": {
    "multi_match" : {
      "query" : "居酒屋 あゆ",
      "fields": ["name^2", "description"]
    }
  }
}

```

参考
* https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html
* https://www.elastic.co/blog/found-fuzzy-search

## [Common Terms](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-common-terms-query.html)

stopwordsを考慮した検索

## [Query String](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-query-string-query.html)

Apache Luceneのクエリシンタックスを使って検索できる。

## [Simple Query String](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-simple-query-string-query.html)

以下のシンタックスを使って検索する

* +: and
* |: or
* -: 含まない
* ": 語句をフレーズとして扱う
* (): グループとして扱う

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "simple_query_string" : {
        "query": "居酒屋 +(あゆ) -花亭",
        "fields": ["name"],
        "default_operator": "and"
    }
  }
}
```

## [Bool Query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html)

must/filter/should/must_notを使ってクエリをフィルタしていく

* must: 必ず語句がドキュメントにマッチしていなければならず、スコアに影響する
* filter: 必ず語句がドキュメントにマッチしていなければならない。ただし、スコアには影響しない
* should: 指定された語句があり、must/filterがなければ、かならず1つ以上の語句がドキュメントにマッチしなければならない。最小のマッチ数は```minimum_should_match```で指定できる
* must_not: 語句がドキュメントに含まれない



## [Range](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-range-query.html)

範囲を指定して検索する。

* gte: 〜以上
* gt: 〜より大きい
* lte: 〜以下
* lt: 〜より小さい
* boost: ブーストの値を設定する

```json
# ファン数が10-20のレストランを探す
GET ldgourmet/restaurant/_search
{
  "query": {
    "range" : {
      "fan_count" : {
        "gte" : 10,
        "lte" : 20
      }
    }
  }
}
```

## [Exists](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-exists-query.html)

値があるフィールドのみを返す。値がない場合は以下。

* null
* []
* [null]
* フィールド自体がない場合

## [Prefix](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-prefix-query.html)

特定のprefixではじまる語句を検索する

## [Wildcard](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-wildcard-query.html)

*と?を使ってワイルドカード検索する

## [Regex](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-regexp-query.html)

正規表現で検索する

## [Fuzzy](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-fuzzy-query.html)

Fuzzy検索をする

## [Ids](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-ids-query.html)

指定のIDにマッチしたクエリを返す

```
GET ldgourmet/restaurant/_search
{
  "query": {
    "ids" : { "values" : ["25030", "25031", "25032"] }
  }
}
```

## [Lite版](https://www.elastic.co/guide/en/elasticsearch/guide/current/search-lite.html)のサーチ

クエリパラメータのみで検索ができる

```
GET ldgourmet/restaurant/_search?q=name:蒙古
```

## [Suggesters](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/search-suggesters-term.html)

もしかして検索などで使うもの。
（注意: 以下は別のindexに対してサーチした。該当のindexのnameフィールドはnot_analyzed設定。）


クエリ

```json
GET restaurants_development/_suggest
{
  "my-suggestion": {
    "text" : "すきやばし小次郎",
    "term": {
      "size" : 5,
      "field": "name"
    }
  }
}
```

結果

```json
{
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "my-suggestion": [
    {
      "text": "すきやばし小次郎",
      "offset": 0,
      "length": 8,
      "options": [
        {
          "text": "すきやばし 次郎",
          "score": 0.875,
          "freq": 1
        },
        {
          "text": "すきやばし次郎",
          "score": 0.85714287,
          "freq": 3
        }
      ]
    }
  ]
}
```

# ソート

```
# 居酒屋でヒットするものをPV順にソートする
GET ldgourmet/restaurant/_search
{
  "query": {
    "term": { "name": "居酒屋" }
  },
  "sort": {
    "access_count": "desc"
  }
}
```

# Mapping

マッピングの内容がみれる

```json
{
  "ldgourmet": {
    "mappings": {
      "restaurant": {
        "properties": {
          "access_count": {
            "type": "integer"
          },
          "address": {
            "type": "string",
            "analyzer": "ngram_analyzer"
          },
          "alphabet": {
            "type": "string"
          },
          "area_id": {
            "type": "string"
          },
...
```

# Index

## [Settings](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/indices-get-settings.html)

Indexの設定値が取得できる

クエリ

```json
GET ldgourmet/_settings
```

結果

```json
{
  "ldgourmet": {
    "settings": {
      "index": {
        "creation_date": "1471317478939",
        "analysis": {
          "analyzer": {
            "ngram_analyzer": {
              "tokenizer": "ngram_tokenizer"
            }
          },
          "tokenizer": {
            "ngram_tokenizer": {
              "token_chars": [
                "letter",
                "digit"
              ],
              "min_gram": "2",
              "type": "nGram",
              "max_gram": "3"
            }
          }
        },
        "number_of_shards": "5",
        "number_of_replicas": "1",
        "uuid": "a83qEcqbTl2M82ri7t7gaw",
        "version": {
          "created": "2030599"
        }
      }
    }
  }
}
```

## [Mapping](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/indices-get-mapping.html)

mappingの情報を取得する


```json
GET ldgourmet/restaurant/_mapping
```


```json
{
  "ldgourmet": {
    "mappings": {
      "restaurant": {
        "properties": {
          "access_count": {
            "type": "integer"
          },
          "address": {
            "type": "string",
            "analyzer": "ngram_analyzer"
          },
          "alphabet": {
            "type": "string"
          },
          "area_id": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "analyzer": "whitespace"
          },
          "category_id1": {
            "type": "string"
          },
          "category_id2": {
            "type": "string"
          },
          "category_id3": {
            "type": "string"
          },
          "category_id4": {
            "type": "string"
          },
          "category_id5": {
            "type": "string"
          },
          "closed": {
            "type": "boolean"
          },
          "created_on": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "analyzer": "ngram_analyzer"
          },
...
```

## [Analyze](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/indices-analyze.html)

アナライザーを指定して試す事ができる。Inquisitorプラグインを使えば同じようなことがもっと効率的には出来る。

```json
GET _analyze
{
  "analyzer" : "standard",
  "text" : "this is a test"
}

GET _analyze
{
  "tokenizer" : "keyword",
  "token_filter" : ["lowercase"],
  "char_filter" : ["html_strip"],
  "text" : "this is a <b>test</b>"
}

# explainをtrueにするとより詳しい結果が見れる。各フィルタごとの結果もわかる。
GET _analyze
{
  "tokenizer" : "keyword",
  "explain": true,
  "token_filter" : ["lowercase"],
  "char_filter" : ["html_strip"],
  "text" : "this is a <b>test</b>"
}
```

## [Stats](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-stats.html)

Indexの統計情報が取れる

```
GET ldgourmet/_stats
```

## [Delete Index](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-delete-index.html)

```
# 作成
PUT twitter
{
  "settings" : {
    "index" : {
      "number_of_shards" : 3, 
      "number_of_replicas" : 2 
    }
  }
}

# 削除
DELETE twitter
```

## [Update Indices Settings](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html)

Indexの設定を更新するには最初にindexをクローズする必要がある

```
# indexを閉じる
POST twitter/_close

# indexを変更する
PUT twitter/_settings
{
  "analysis" : {
    "analyzer":{
      "content":{
        "type":"custom",
        "tokenizer":"whitespace"
      }
    }
  }
}

# indexを開く
POST twitter/_open
```

# [Explain](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/search-explain.html)

ドキュメントがどのようにマッチしたのか詳細に表示してくれる。

クエリ

```json
GET ldgourmet/restaurant/326659/_explain
{
  "query": {
    "term": { 
      "name": "居酒屋"
    }
  }
}
```

結果

```json
{
  "_index": "ldgourmet",
  "_type": "restaurant",
  "_id": "326659",
  "matched": true,
  "explanation": {
    "value": 2.787416,
    "description": "sum of:",
    "details": [
      {
        "value": 2.787416,
        "description": "weight(name:居酒屋 in 11156) [PerFieldSimilarity], result of:",
        "details": [
          {
            "value": 2.787416,
            "description": "fieldWeight in 11156, product of:",
            "details": [
              {
                "value": 1,
                "description": "tf(freq=1.0), with freq of:",
                "details": [
                  {
                    "value": 1,
                    "description": "termFreq=1.0",
                    "details": []
                  }
                ]
              },
              {
                "value": 5.574832,
                "description": "idf(docFreq=851, maxDocs=82654)",
                "details": []
              },
              {
                "value": 0.5,
                "description": "fieldNorm(doc=11156)",
                "details": []
              }
            ]
          }
        ]
      },
      {
        "value": 0,
        "description": "match on required clause, product of:",
        "details": [
          {
            "value": 0,
            "description": "# clause",
            "details": []
          },
          {
            "value": 0.1793776,
            "description": "_type:restaurant, product of:",
            "details": [
              {
                "value": 1,
                "description": "boost",
                "details": []
              },
              {
                "value": 0.1793776,
                "description": "queryNorm",
                "details": []
              }
            ]
          }
        ]
      }
    ]
  }
}
```

## [Index Templates](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html)

index templateを使うと、mappingsやsettingsのテンプレートを作っておけ、マッチする文字列のindexが作成されたときに自動的にそのmappingsやsettingsが適用できます。
なお、複数のテンプレートが同時にマッチした場合は、orderで適用順序を制御できます。orderは小さい数字のほうが先に適用されます。

```json
# テンプレート一覧取得
GET _template/
```

# [cat APIs](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/cat-alias.html)

## aliases
indexに対応付けられたaliasを取得する

クエリ

```
GET _cat/aliases
```

結果。以下はsearchkickを使ったために作られたalias

```
alias                   index                                     filter routing.index routing.search 
restaurants_development restaurants_development_20160821161429131 -      -             -              
areas_development       areas_development_20160821135301707       -      -             -              
prefs_development       prefs_development_20160821133713704       -      -             -              
ratings_development     ratings_development_20160821160422911     -      -             -              
articles_development    articles_development_20160819111717137    -      -             -              
```

## その他

一部Cluster APIを同じ情報を返すものもある

* ```GET _cat/allocation?v```: それぞれのシャードがどのくらいのdiskを使っているか　
* ```GET _cat/indices?v```: 各インデックスのドキュメントのが詳細に見れる
* ```GET _cat/fielddata?v```: 各ノードでどれくらいのヒープメモリが使われているか
* ```GET _cat/health?v```: クラスターが正しく動いているかの健康状態を表示
* ```GET _cat/nodes?v```: 各ノードの状態を表示　
* ```GET _cat/pending_tasks?v```: いま実行されてたり待たされているジョブを表示
* ```GET _cat/plugins?v```: インストールしているプラグインを表示
* ```GET _cat/shards?v```: シャードの情報を表示。インデックスごとのドキュメントの量と使用量がわかる。
* ```GET _cat/segments?v```: セグメントの情報がわかる

# [Validate API](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/search-validate.html)

詳しく知りたい場合は[Validate APIの利用](http://blog.johtani.info/blog/2014/10/27/how-to-use-validate-api/)が参考になります。

以下クエリと実行した結果です。ただ、この場合は、

```json
GET ldgourmet/_validate/query?explain
{
  "query": {
    "match_al": {}
  }
}
```

結果

```json
{
  "valid": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "explanations": [
    {
      "index": "ldgourmet",
      "valid": false,
      "error": "org.elasticsearch.index.query.QueryParsingException: No query registered for [match_al]"
    }
  ]
}
```

また、validate APIは検索がどのような単語に変換されて行われたかもわかる

クエリ

```json
GET ldgourmet/_validate/query?explain
{
  "query": {
    "multi_match": {
      "fields": ["name","name_kana","description"],
      "query": "すきやばし"
    }
  }
}
```

結果

```json
{
  "valid": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "explanations": [
    {
      "index": "ldgourmet",
      "valid": true,
      "explanation": "((name:すき name:すきや name:きや name:きやば name:やば name:やばし name:ばし) | (description:すき description:すきや description:きや description:きやば description:やば description:やばし description:ばし) | (name_kana:すき name_kana:すきや name_kana:きや name_kana:きやば name_kana:やば name_kana:やばし name_kana:ばし))"
    }
  ]
}
```

# [Cluster API](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/cluster-nodes-stats.html)

## [Node Stats](https://www.elastic.co/guide/en/elasticsearch/reference/2.3/cluster-nodes-stats.html)

nodeの統計情報を詳しく見れる。リクエストのqueueが溜まっているとかも見れる

```
GET _nodes/stats
```

# 応用

ここからはニーズのありそうなクエリを組み立てていきます。

## 蒙古タンメン中本が何件あるか調べる

時々蒙古タンメンをためだくなるのですが、中本は何件あるのでしょうか。調べてみましょう。
結果は10件でした。default_operatorをandにしないと中本以外も他のタンメン屋さんがヒットしてしまいます。

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "simple_query_string" : {
        "query": "蒙古タンメン",
        "fields": ["name"],
        "default_operator": "and"
    }
  }
}
```

さて、食べたくなったので中目黒にあるか調べてみます。

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "simple_query_string" : {
        "query": "蒙古タンメン 中目黒",
        "fields": ["name", "address"],
        "default_operator": "and"
    }
  }
}
```

ないですね。。。では中目黒に近い順に並べてみましょう。[こちら](https://www.elastic.co/guide/en/elasticsearch/guide/current/sorting-by-distance.html)を参考に組み立ててみます。まず中目黒駅の緯度経度を調べます。[Googleマップで緯度・経度を求める](http://user.numazu-ct.ac.jp/~tsato/webmap/sphere/coordinates/advanced.html)というサイトがあったので、やってみると(緯度(latitude), 経度(longitude)) = (35.644288, 139.699096)と出ました。

```json
GET ldgourmet/restaurant/_search
{
  "query": {
    "simple_query_string" : {
        "query": "蒙古タンメン",
        "fields": ["name"],
        "default_operator": "and"
    }
  },
  "sort": [{
    "_geo_distance": {
      "location": {
        "lat": 35.644288,
        "lon": 139.699096
      },
      "order": "asc",
      "unit": "km",
      "distance_type": "plane"
    } 
  }]
}
```

結果は以下です。渋谷が一番近いようです。

```json
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 10,
    "max_score": null,
    "hits": [
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "407978",
        "_score": null,
        "fields": {
          "name": [
            "蒙古タンメン中本"
          ],
          "address": [
            "渋谷区道玄坂2-6-17渋東シネタワー　B2"
          ]
        },
        "sort": [
          1.3264480838396593
        ]
      },
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "16628",
        "_score": null,
        "fields": {
          "name": [
            "蒙古タンメン中本"
          ],
          "address": [
            "品川区上大崎2-13-45トランスリンク第3ビル1階"
          ]
        },
        "sort": [
          2.7366820396931413
        ]
      },
...
```

さらにKibanaで視覚的に中本がどこにあるのか確かめてみます。Kinabaについての使い方を知りたい場合は[KPIダッシュボードとして使うKibana4](http://qiita.com/gggami/items/078966284129331e4db7)がいいかなと思います。```name:"蒙古タンメン中本"```でしぼると以下のようになります。

データセット自体は若干古いですが、横浜にもあるのですね。

![image](https://qiita-image-store.s3.amazonaws.com/0/30079/2c40b9ba-df56-85ec-ff4c-82393128acd3.png)

## ランチをしに中目黒から徒歩でいけるラーメン屋を探す

検索条件は以下です
* ランチがやっている: open_lunch=1
* 徒歩で行ける: 中目黒駅から0.8km以内 [参考](https://www.elastic.co/guide/en/elasticsearch/guide/current/geo-distance.html)
* ラーメン屋: nameまたはdescriptionにラーメンが含まれる

クエリ

```json
GET ldgourmet/restaurant/_search
{
  "size": 100,
  "fields": ["name", "address", "description"],
  "query": {
    "filtered": {
      "query": {
        "simple_query_string" : {
          "query": "ラーメン",
          "fields": ["name", "description"],
          "default_operator": "and"
        }
      },
      "filter": {
        "geo_distance": {
          "distance":      "0.8km",
          "distance_type": "plane", 
          "location": {
            "lat": 35.644288,
            "lon": 139.699096
          }
        }
      }
    }
  }
}
```

結果

```json
{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 8,
    "max_score": 2.0545835,
    "hits": [
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "14956",
        "_score": 2.0545835,
        "fields": {
          "name": [
            "ラーメン香月"
          ],
          "address": [
            "目黒区青葉台１-２９-１２セブンスターマンション第二青葉台1階"
          ]
        }
      },
      {
        "_index": "ldgourmet",
        "_type": "restaurant",
        "_id": "309908",
        "_score": 1.6692734,
        "fields": {
          "name": [
            "屋台系ラーメン 魚鳥"
          ],
          "description": [
            "山手通り沿い。"
          ],
          "address": [
            "目黒区東山2-2-5"
          ]
        }
      },
      {
        "_index": "ldgourmet",
...
```

さてこの場合、総合的に、人気があるかとか、語句のラーメンへの関連度が高いとか、距離とかはは考慮されていません。その場合自分で[Funciton Score](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html)を定義してスコアを以下のように独自に決めれます。


```json
GET ldgourmet/restaurant/_search
{
  "size": 100,
  "fields": ["name", "access_count", "address", "description"],
  "query": {
    "filtered": {
      "query": {
        "function_score": {
          "query": {
            "simple_query_string" : {
              "query": "ラーメン",
              "fields": ["name", "description"],
              "default_operator": "and"
            }
          },
          "boost_mode": "multiply",
          "script_score": {
            "script": "_score * doc['access_count'].value"
          }
        }
      },
      "filter": {
        "geo_distance": {
          "distance":      "0.8km",
          "distance_type": "plane", 
          "location": {
            "lat": 35.644288,
            "lon": 139.699096
          }
        }
      }
    }
  }
}
```

# 参考
* https://www.elastic.co/guide/en/elasticsearch/reference/current/_the_search_api.html
* https://www.elastic.co/guide/en/elasticsearch/guide/current/search.html
* http://qiita.com/wapa5pow/items/cf3c1bc66df403a930ab
* [Elasticsearch を使った位置情報検索 - クックパッド開発者ブログ](http://techlife.cookpad.com/entry/2015/03/12/080000)