sakutarou’s blog

とりあえずWeb系技術をゆるく書いていく

やっとElasticsearchのクエリーでドキュメントの検索ができた

検索のやり方を備忘録として残しておく
データにはElasticsearchのサンプルデータを利用しています。

www.elastic.co

全文検索クエリ:単語一致

単語単位で検索する場合
RDBのLIKEに近いけどあくまで単語単位での検索

例1) 住所に単語として Street が含まれるドキュメントを検索する

curl -Xget "http://172.17.0.2:9200/bank/account/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "address" : "Street"
    }
  }
}'

例2)住所に Elton 又は Street が含まれているドキュメントを検索する(※RDBでいうところのOR検索)

※半角スペースで区切ることで、複数条件での検索になる

curl -Xget "http://172.17.0.2:9200/bank/account/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "address" : "Elton Street"
    }
  }
}'

例3)住所に Elton 且つ Street が含まれているドキュメントを検索する(※RDBでいうところのAND検索)

※半角スペースで区切ることで、複数条件での検索になる ※AND検索する場合は、operatorを指定する

curl -Xget "http://172.17.0.2:9200/bank/account/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "address" : {
        "query": "Elton Street",
        "operator": "and"
      }
    }
  }
}'

例4) ヒット率での検索

最低N個以上キーワードが含まれていること といったようなRDBにない検索が可能。 minimum_should_match に含まれていてほしい 個数 OR 割合(%) が指定可能である

以下の場合は Elton Street Putnam Place Rockwell Avenue のうち2個以上含まれている結果が取得できる

curl -Xget "http://172.17.0.2:9200/bank/account/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "address" : {
        "query": "Elton Street Putnam Place Rockwell Avenue",
        "minimum_should_match": 2
      }
    }
  }
}'

Termクエリ

Termクエリ

Termクエリはkeyword型に対して検索を行う。

ドキュメント格納時
  • text型はアナライザが単語分割を行って転置インデクスを構築する
  • keyword型はドキュメントにそのまま格納される

検索

  • text型は転置インデクスを利用して検索が行われる
  • keyword型は格納されたドキュメントと検索キーワードを直接比較する

また、termクエリは格納されている文字列と完全一致するものを検索する(大文字・小文字も含めて比較する)

例)

curl -Xget "http://172.17.0.2:9200/bank/account/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "term": {
      "address": "171 Putnam Avenue"
    }
  }
}'

Elasticsearchのdate型でInvalid format言われた場合の対処方法

こんな感じのマッピングを作成して、 accesstime2018/08/16 19:00:00 のような日時を入れたら Invalid format 言われた場合 format を指定したら解決
elasticsearch的にこの方法がいいのかは検討する必要あるけど、とりあえず今はこれでOK

修正前

curl -XPUT "http://172.17.0.2:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_type": {
      "properties" : {
        "host": {"type":"keyword"},
        "method": {"type":"keyword"},
        "accesstime": {"type": "date"}
      }
    }
  }
}'

修正後

curl -XPUT "http://172.17.0.2:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_type": {
      "properties" : {
        "host": {"type":"keyword"},
        "method": {"type":"keyword"},
        "accesstime": {
          "type": "date",
          "format": "yyyy/MM/dd HH:mm:ss"
        }
      }
    }
  }
}'

kibanaを起動する(Docker)

今回はkibanaを起動してみます。
kibanaも基本的には公式を参考とすれば問題ありません。

Elasticsearchの起動はこちらをどうぞ

kozo.hatenablog.jp

www.elastic.co

Dockerイメージを取得

docker pull docker.elastic.co/kibana/kibana:6.3.2

イメージ名を変更する

前回同様、イメージ名が長すぎて使いづらいのでイメージ名を変更します。

docker tag {取得したイメージID} kibana:6.3.2

# 変更前は削除
docker rmi docker.elastic.co/kibana/kibana:6.3.2

起動

kibanaを起動します。
ELASTICSEARCH_URL にはElasticsearchのURLを指定します。
※Elasticsearchの起動時に名前を指定しておいた方がよさそうですね

 docker run -p 5601:5601 -e "ELASTICSEARCH_URL=http://IPアドレス:9200" kibana:6.3.2

アクセス

kibanaにアクセスします。
IPアドレスにはdockerホストのアドレスを指定します。

http://IPアドレス:5601

こんな画面が出ればOK!
f:id:sakutarou:20180729231749p:plain

とりあえずここまで!

PHPStormでファイル名検索ができなくなったらすること

たまーにPHPStromでファイル名検索しようとすると検索候補として何も表示されない(ログとか一部なぜか表示される)状況に悩まされていたけど解決したので残しておきます。

メニューから以下を実行

[ファイル]-[キャッシュの破棄/再起動]-[破棄して再起動]
※日本語化してあります

再起動後通常通り検索できるはず!

Elasticsearchドキュメント操作の基本

ドキュメントの登録

PUT

IDを指定して登録します。
IDに使える文字は半角英数っぽい

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/ID

例)

curl -XPUT http://localhost:9200/my_index/my_type/1 \
-H 'Content-Type: application/json' -d'
{
    "name": "kozo",
    "address": "japan",
    "message": "hello world"
}
'

POST

IDはランダムな英数で自動採番される。
他にPUTとの違いがあるのかな?

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/

例)

curl -XPOST http://localhost:9200/my_index/my_type \
-H 'Content-Type: application/json' -d'
{
    "name": "kozo",
    "address": "japan",
    "message": "hello world"
}
'

ドキュメントの取得

ID指定での取得方法です。

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/ID

例)

curl -XGET http://localhost:9200/my_index/my_type/1
curl -XGET http://localhost:9200/my_index/my_type/1?pretty
curl -XGET http://localhost:9200/my_index/my_type/1/_source?pretty
  • ?pretty を指定することでレスポンスを見やすくフォーマットしてくれます
  • _source を指定すると登録内容のみが取得できます

ドキュメントの検索

とりあえず完全一致

APII形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/_search

例)

curl -XGET http://localhost:9200/my_index/my_type/_search?pretty -H 'Content-Type: application/json' -d'
{
    "query" : {
        "match" : {
            "name": "kozo"
        }
    }
}'

検索範囲

# my_typeの中から検索
http://localhost:9200/my_index/my_type/_search?pretty
# my_indexの中から検索
http://localhost:9200/my_index/_search?pretty
# 複数indexの中から検索
http://localhost:9200/my_index,my_index2/_search?pretty
# ワイルドカード指定
http://localhost:9200/my_index*/_search?pretty
# 全体から検索
http://localhost:9200/_search?pretty

ドキュメントの全体更新

PUTでドキュメントの全体を更新します

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/ID

例)

curl -XPUT http://localhost:9200/my_index/my_type/1 \
-H 'Content-Type: application/json' -d'
{
    {
        "name": "kozo",
        "address": "japan",
        "message": "hello world"
    }
}
'

ドキュメントの一部更新

更新だけど、 POST を発行するみたい。
内部的には削除 => 再登録なのかな? doc を指定して送信します

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/ID/_update

例)

curl -XPOST 'http://192.168.10.11:9200/my_index/my_type/1/_update?pretty' -H 'Content-Type: application/json' -d'
{
    "doc": {
        "user_name": "kozo(update test)"
    }
}
'

ドキュメントの削除

ID指定で削除する

API形式

http://ホスト:9200/インデックス名/ドキュメントタイプ名/ID

例)

curl -XDELETE http://192.168.10.11:9200/my_index/my_type/1?pretty

インデックスの作成

インデクスを作成せずにドキュメントの登録を行うとElasticsearchが自動的にインデックスを作成している。
インデックスを明示的に作成する必要があるタイミングは以下ののような デフォルト値 でインデックスを作成したくない場合となる

  • レプリカ数を変更したい場合
  • シャード数を変更したい場合(特にシャード数はインデックス作成時のみにしか変更することは出来ない)

API形式

http://ホスト:9200/インデックス名

例)

curl -XPUT "http://192.168.10.11:9200/my_index3" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  }
}'

例2) すべてを書略した場合

curl -XPUT "http://192.168.10.11:9200/my_index3"

インデックスの設定情報取得

API形式

http://ホスト:9200/インデックス名/_settings

例)

curl -XGET "http://192.168.10.11:9200/my_index3/_settings?pretty"

インデックス設定の更新

API形式

http://ホスト:9200/インデックス名/_settings

例)

curl -XPUT "http://192.168.10.11:9200/my_index3/_settings" -H 'Content-Type: application/json' -d'
{
  "index": {
    "number_of_replicas": 3
  }
}'

インデックスの削除

API形式

http://ホスト:9200/インデックス名

例)

curl -XDELETE "http://192.168.10.11:9200/my_index3"

Elasticsearchの用語

自分の備忘録的に書いておきます
徐々に増やす予定

インデックス

RDBでの DB に相当する。

ドキュメントタイプ

RDBでの テーブル に相当する
ドキュメントタイプの中に含まれるフィールドのデータ構造やデータ型を記述したものを マッピング と呼ぶ

ドキュメント

RBDでの 1レコード に相当する。
一般的なRDBとの違いは JSONオブジェクトを保存するところである。

IDはインデックスへのドキュメントを格納するタイミングで自動採番される。

フィールド

RDBでの カラム に相当する。
ElasticsearchのドキュメントはJSONになっているので、 フィールドは JSONの「キー:バリュー」の一組になる。

基本的にはフィールド単位ので検索となる。

型としては、 text, long, short, integer, float, date, boolean など基本的にそろっている

Node

サーバーとイコール?

Shard

1つのインデックスは複数のShardから構成されている?
Shardを増やすと基本的には性能があがる?

デフォルト値とことなるShard数を持つIndexを作成したい場合は明示的に作成する

Replica

Shardとの違いがあまり分かってない。

Elasticsearchの起動 (Docker)

Elasticsearchを今まで使ってこなかったのですが、必要に迫られて使うことに。
新しくて・基礎から丁寧に説明してある、いい書籍があったのでこれを読みながら頑張ってみます。

とりあえず起動

Dockerにimageがあったので起動してみようと思ったのですが3つimageが存在するようです。

一番上に Official Repository と書いてあったのでこれを使っていたのですがどうやら違うようです。
Descriptionに DEPRECATION NOTICE 書いてあった。。。。

ちゃんと英語読まなきゃね。。。

2つ目、3つ目は同じようですが、 3つめが公式サイトになるので、今回は3つ目を使用します。
実践ガイドの書籍も3つ目を使用しています。

こんどこそ起動

基本的には、公式に丁寧に書いてあります。

www.elastic.co

イメージを取ってきます

docker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.1

イメージ名を変更する

公式サイトでは名前の変更をしてないので変更する必要はないのですが、このままだとイメージ名が長いので elasticsearch:6.3.1 に変更しちゃいます。

docker tag {取得したイメージID} elasticsearch:6.3.1

# 変更前は削除
docker rmi docker.elastic.co/elasticsearch/elasticsearch:6.3.1

起動

docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:6.3.1

動作確認

curl http://192.168.10.11:9200/_cat/health

# こんな値が帰ってくればOK!
> 1532148126 04:42:06 docker-cluster green 1 1 0 0 0 0 0 0 - 100.0%

これでとりあえず実行環境はそろいました。