ElasticsearchのRESTfull API

# RESTfull　API

Elasticsearchは直接APIを叩くだけで操作できることは特徴の一つであり、公式には沢山APIを用意してくれてます。いくつ代表的なAPIを実際に操作してみたいと思います。

## 事前準備

* [Elasticsearchサーバー構築](https://qiita.com/syouekiko/items/d43888c2319b1cd709df)
* [Elasticsearch-head構築](https://qiita.com/syouekiko/items/d43888c2319b1cd709df#elasticsearch%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5)
* API操作ツール
以下のいずれ使えばよいです。

  * Advanced REST clientプラグイン
  * Postmanプラグイン
  * Curl(Elasticsearchサーバーのターミナルで操作)
  * Kibana の Dev Tools
* onlineツール[Json Viewer](http://jsonviewer.stack.hu/)

## Advanced REST clientの利用方法
Advanced REST clientをインストール後、アプリ→ARCのマークでAPIを使用することができる。
![api.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/d0ce1467-3d2e-2e5c-57b0-ed5a8c9bc8c1.png)
このツールを使わない場合にはターミナルにて以下のようにコマンド操作でもできます。
例：

```
& curl -XPUT http://localhost:9200/dic
 {"ok":true,"acknowledged":true}
```

# API応用
## インデックス作成・削除(Index APIs)
公式：https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html#indices
以下は公式のサンプルコードです。

```ruby:リクエスト
PUT /my-index-000001
{
  "settings": {
    "index": {
      "number_of_shards": 3,  
      "number_of_replicas": 2 
    }
  }
}
```
今回 indexの名前はmail-indexとする

```ruby:リクエスト
URL:
PUT /mail-index
Content type: application/jaso
body: 
{
  "settings": {
    "index": {
      "number_of_shards": 3,  
      "number_of_replicas": 2 
    }
  }
}
```
「SEND」をクリックする
![index3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/1b8439a5-250a-321d-a633-e708c68626fe.png)
200帰ってきた。できたようです。
![index5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/9ab24d1c-51fa-f143-f9de-23a6361df48b.png)

もう一回elasticsearch-headにも確認します。
http://xxx.xxx.xxx.xxx:9100/ にアクセスする。mail-indexが作成されました。
![index6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/4ce73b3d-cc96-b3e0-7462-fca1c7622910.png)

インデックス削除の場合

```ruby:構文
DELETE /{インデックス名}/
```

## データー挿入(Document APIs)

* id指定式

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html

```ruby:構文
POST /{インデックス名}/{タイプ名}/{id}
```
実際やってみよ～

```ruby:リクエスト
URL部分：
POST /mail-index/user_info/1001

body部分：
{
  "ユーザID":1001,
  "ユーザ名":"鈴木太郎",
  "ステータス":0,
  "メール":"suzukitaro@gmail.com"
}
```

```ruby:レスポンス
{
"_index": "mail-index",
"_type": "user_info",
"_id": "1001",
"_version": 1,  →　ここ注意
"result": "created",
"_shards": {
"total": 3,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
```
結果確認
![doc1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/c40d3d6a-d2c0-90c0-105a-58f485d640e3.png)

* id指定なし式

```ruby:構文
POST /{インデックス名}/{タイプ名}
```
実際やってみよ～

```ruby:リクエスト
URL部分：
POST /mail-index/user_info

body部分：
{
  "ユーザID":1002,
  "ユーザ名":"田中博",
  "ステータス":0,
  "メール":"tanaka.hiroshi@gmail.com"
}
```

```ruby:レスポンス
{
"_index": "mail-index",
"_type": "user_info",
"_id": "r8qdj3oB7A0XUeSyl8-h",
"_version": 1,
"result": "created",
"_shards": {
"total": 3,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
```
結果確認
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/d3fe2f84-f9a3-79b6-8ff4-56246cac6022.png)

<font color="Red">id指定しない場合には自動にidが生成されることが分かった。</font>

## データー更新(Document APIs)

* 全部更新

idは1001のユーザーのステータスを1に変更する

```ruby:構文
PUT /{インデックス名}/{タイプ名}/{id}
```


```ruby:リクエスト
URL部分：
PUT /mail-index/user_info/1001

body部分：
{
  "ユーザID":1001,
  "ユーザ名":"鈴木太郎",
  "ステータス":1,
  "メール":"suzukitaro@gmail.com"
}
```

```ruby:レスポンス
{
"_index": "mail-index",
"_type": "user_info",
"_id": "1001",
"_version": 2,　　　　→　ここ注目
"result": "updated",  →　ここ注目
"_shards": {
"total": 3,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
```
結果確認
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/b1607cec-d38b-b05d-bccf-35757f943548.png)

* 一部更新

idはr8qdj3oB7A0XUeSyl8-hのユーザーのメールアドレスをyahoo.co.jpにする

```ruby:構文
POST /{インデックス名}/{タイプ名}/{id}/_update
```

```ruby:リクエスト
URL部分：
POST /mail-index/user_info/r8qdj3oB7A0XUeSyl8-h/_update

body部分：
{
 "doc":{
  "メール": "tanaka.hiroshi@yahoo.co.jp"
 }
}
```
<font color="Red">↑部分更新のため、属性すべて入れる必要がなく、必要な属性だけでよい。</font>

```ruby:レスポンス
{
  "_index": "mail-index",
  "_type": "user_info",
  "_id": "r8qdj3oB7A0XUeSyl8-h",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 3,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}
```

結果確認
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755874/0cd2d39c-e764-4836-a403-082b30cd07ea.png)


## データー削除・検索(Document APIs)

* 削除

```ruby:構文
DELETE /{インデックス名}/{タイプ名}/{id}
```

```ruby:リクエスト
URL部分：
DELETE /mail-index/user_info/1001
```

存在しないidを削除すると404が返ってくる。

* 一部検索

```ruby:構文
GET /{インデックス名}/{タイプ名}/{id}
```

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/1001
```

```ruby:レスポンス
{
"_index": "mail-index",
"_type": "user_info",
"_id": "1001",
"_version": 2,
"_seq_no": 2,
"_primary_term": 1,
"found": true,
"_source": {
"ユーザID": 1001,
"ユーザ名": "鈴木太郎",
"ステータス": 1,
"メール": "suzukitaro@gmail.com"
}
}
```
* 全部検索

```ruby:構文
GET /{インデックス名}/{タイプ名}/_search
```

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search
```
<font color="Red">全部検索しても、登録済みの10件しか返ってこない。全件取得したい場合にはまた別途紹介する。</font>

* キーワード検索

```ruby:構文
GET /{インデックス名}/{タイプ名}/_search?q=XXX:X
```

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search?q=ステータス:1
```
```ruby:レスポンス
{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "mail-index",
        "_type": "user_info",
        "_id": "1001",
        "_score": 1,
        "_source": {
          "ユーザID": 1001,
          "ユーザ名": "鈴木太郎",
          "ステータス": 1,
          "メール": "suzukitaro@gmail.com"
        }
      }
    ],
    
  }
}
```

## DSL検索

Query DSLといい、複雑な検索に使われる。

```ruby:構文
POST /{インデックス名}/{タイプ名}/_search
```

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search

Body部分：
{
 "query":{
   "match":{
  "ステータス": 1
   }
 }
}
```
```ruby:レスポンス
{
"took": 3,
"timed_out": false,
"_shards": {
  "total": 3,
  "successful": 3,
  "skipped": 0,
  "failed": 0
},
"hits": {
  "total": {
    "value": 1,
    "relation": "eq"
  },
  "max_score": 1,
  "hits": [
    {
      "_index": "mail-index",
      "_type": "user_info",
      "_id": "1001",
      "_score": 1,
      "_source": {
        "ユーザID": 1001,
        "ユーザ名": "鈴木太郎",
        "ステータス": 1,
        "メール": "suzukitaro@gmail.com"
      }
    }
  ],
  
}
}
```
* 複数条件の場合

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search

Body部分： 年齢30以上ステータス1となる
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "age": {
            "gt": 30
          }
        }
      }
    },
    "must": {
      "match": {
        "ステータス": 1
      }
    }
  }
}
```
* 全文検索

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search

Body部分： 鈴木 田中が含まれるデーター
{
 "query":{
   "match":{
     "ユーザ名": "鈴木 田中"
   }
 }
}
```
## ドキュメント存在チェック

* 方法①

レスポンスにある「"found": true,」を確認する、true→存在、false→存在なし

* 方法②

レスポンスコードで判断する。

```ruby:リクエスト
URL部分：
HEAD /{インデックス名}/{タイプ名}/{id}
```

```ruby:レスポンスコード
200　→　存在
404　→  存在しない
```

## ハイライト

```ruby:リクエスト
URL部分：
GET /mail-index/user_info/_search

Body部分： 鈴木 田中が含まれるデーター
{
  "query": {
    "match": {
      "ユーザ名": "鈴木 田中"
    }
  },
  "highlight": {
    "fields":{
      "ユーザ名": {
        
      }
    }
  }
}
```
```ruby:レスポンス
{
  "took": 55,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.4723402,
    "hits": [
      {
        "_index": "mail-index",
        "_type": "user_info",
        "_id": "r8qdj3oB7A0XUeSyl8-h",
        "_score": 1.4723402,
        "_source": {
          "ユーザID": 1002,
          "ユーザ名": "田中博",
          "ステータス": 0,
          "メール": "tanaka.hiroshi@yahoo.co.jp"
        },
        "highlight": {
          "ユーザ名": [
            "<em>田</em><em>中</em>博"
          ],
          
        }
      },
      {
        "_index": "mail-index",
        "_type": "user_info",
        "_id": "1001",
        "_score": 1.3097506,
        "_source": {
          "ユーザID": 1001,
          "ユーザ名": "鈴木太郎",
          "ステータス": 1,
          "メール": "suzukitaro@gmail.com"
        },
        "highlight": {
          "ユーザ名": [
            "<em>鈴</em><em>木</em>太郎"
          ],
          
        }
      }
    ],
    
  }
}
```

# 余談

いくつコツをご紹介します。

* ブラウザでJson式表示

ブラウザでそのままAPIを叩いても良いですが、形式がちょっと変です。
その時最後「?pretty」を入れると、Json式で表示される。

例：http://xxx.xxx.xxx.xxx:9200/mail-index/user_info/_search?pretty

* 検索情報を選定したい
検索した情報が_sourceに全部入ってますね。
不要な情報も入ってるため、必要な情報だけ検索したい場合には以下のようなURLにすればよいです。

例：http://xxx.xxx.xxx.xxx:9200/mail-index/user_info/_search?_source=ステータス

そうすると_source内のステータス情報だけ取得する。

* _sourceだけほしい

rawのデーターだけほしい場合は以下のように取得する

例：http://xxx.xxx.xxx.xxx:9200/mail-index/user_info/1001/_source?_source=ステータス