ぴょこりんブログ

裏垢です。

Elasticsearchに遊ばれてみた話。

はじめに

最近、かなり今更感があるがElasticsearchを触っている。一昔前いろんな人が便利だ便利だと騒いでいた気がする。完全に出遅れたが今より遅いことはない。僕はElasticsearchに興味があるのだ。

公式サイトを見てみよう。

www.elastic.co

Elasticsearchは、様々なユースケースを解決する分散型RESTful検索/分析エンジンです。予期した結果や、そうでないものも検索できるようにデータを集めて格納するElastic Stackのコア製品です。

もうこのフレーズだけで理解し難い。RESTfulと検索エンジンはわかる。気になるのは残りだ。分析は検索と一緒に並ぶには随分曖昧な言葉に感じられる。『様々なユースケースを解決する分析エンジン』、かなりふわみ*1がある。

だがしかしそんなElasticsearch、多くの方々が活用している。僕は実は本当に『様々なユースケースを解決する分析エンジン』なのでは無いかと思っている。それはまるで言語仕様として尖った強みは無いけれど、あまりに色々と充実しすぎているpythonのような、そんな感じなのではないかと。きっと僕はElasticsearchを好きになれる。そんな気がしたのだ。

今日はそんな僕が手探りでElasticsearchと仲良くなろうとする、その過程で得られた思い出をいくつか切り取って紹介しようと思う。

前提知識的なアレ

とにかく最初はElassticsearchがなんだかよくわからなかったので、Key-Value Store的に使ってみた、そんな感じだ。 そう、たとえば、python向けIFを使って、

es = Elasticsearch()  
doc = {  
    'お名前': 'ぴょりこ',  
    'やること': 'ブログを書く'  
}  
res = es.index(index="test-index1", doc_type='pyokopyoko', body=doc)  

とやったら、何やら書き込めて、

res = es.search(index="test-index1", body={"query": {"match": { 'お名前': 'ぴょりこ'}}})

で、マッチしたものを引っ張り出せる、程度の雑な認識である。そんな前提で色々トラブった話をしよう。

Elasticsearchとの思い出

型を意識しろ

Elasticsearchはデータがブチこまれたとき、その入力から勝手に型を推定してくれる(もちろん自分で定義もできる)。dateとかfloatとか色々。 ただし、同じkeyだったら同じ型でなきゃいけないという縛りがある。

まぁそりゃそうかぁという感じなのだけれど、こちらはガバガバpython使いなのでたとえば以下のようなことをしてエラーを吐かせた。

docs =[ {  
    'お名前': 'ぴょりこ',  
    '身長': '143.3'  
},
 {  
    'お名前': 'test',  
    '身長': '0'  
}
]  
for doc in docs:
    res = es.index(index="test-index2", doc_type='pyokopyoko', body=doc)  

一個目の身長で型がfloatと推定されたあと、二個目でintをブチこもうとしてるので怒られる。testさんの身長を0でなく0.0にすると怒られない。if文で例外に0を返す的なやつを書いてたら(これはコレで明示的にNoneとかにすべきケースな気がするが。)、これに引っかかって何が起こってるのかわからなくなり悩んだ。

同様のやらかしとして、たまに空欄が存在する日付データを食わせていたとき、通常はdate型だが空欄だけstringと解釈されて同じように怒られた。このときは、Noneはdate型として受け入れてくれるので、空欄をNoneに置換してから食わせた。

python書いていて普段自分がいかに型を意識していなかったかがわかる。

汎用key-value storeだと思って深いやつぶち込んだ

深い階層のjson的なデータの書き込みをしてみた。

 {  
    'お名前': 'ぴょこ',  
    {'2018/12/1': ['','',...]  
     '2018/12/1': ['','',...],
     ...  
}  
}

みたいな階層が深かったりリストが混じってて長さが可変だったりするやつ。件数を増やしていくにつれめちゃめちゃ重くなって150件程度でサービスが死んだので*2、こういう使い方するんじゃないんだぁと思いました(こなみかん)。

というか各key(この呼び方が正しいかわからない)ごとに型定義したりしてるんだから、複雑な構造にしたらその分このあたりの手間も増えそうだしそれはまぁそうかぁという感じ。

せっかく検索が早いのだから、一箇所に色々集めて複雑な構造にせず、できるだけ浅い階層のものでインデックスを構成して、複数のインデックスからサーチして横断的にデータを眺めるみたいな使い方をするものなのだろうなぁという気持ちになりました。

そのへんの情報が古くて困る

Elasticsearch用語であるところのindexとtype、検索すればわかると思うんだけれどみんなSQLでいうとindexがDBでtypeがテーブルとか言ってる。

公式曰くtypeは廃止される予定で、

Initially, we spoke about an “index” being similar to a “database” in an SQL database, and a “type” being equivalent to a “table”.
This was a bad analogy that led to incorrect assumptions.

www.elastic.co

まぁそういうこともある。index設計のベストプラクティスはまだよくわからない。雰囲気でElasticsearchをやっている。

matchはゆるふわ検索

最初の頃matchは完全一致だと思ってたんだけど、そんなことはなかった。

docs =[ {  
    'お名前': 'ぴょりこ',  
    '機材': 'SC-88'  
},
 {  
    'お名前': 'まおん',  
    '機材': 'SC-55'  
},
 {  
    'お名前': 'れがしーちゃん',  
    '機材': 'SD-90'  
}
]  
for doc in docs:
    res = es.index(index="test-index3", doc_type='pyokopyoko', body=doc)  

とデータぶち込んで、

res = es.search(index="test-index3", body={"query": {"match": { '機材': 'SC-88'}}})

とクエリを投げると何故かSC-55を持ってるまおんも返ってくる。どうも単純な完全一致ではなく、”-”で単語が区切りられてると解釈して、多分 or的に区切られた単語にマッチするものを見つけてくるっぽい(要確認)。

というわけでSCがついてるものを返してくれる感じの挙動になる。多分スペース区切りとかでも多分そんな感じに振る舞うんじゃないかな(要確認)。

matchをmatch_phraseなどにすると所望の挙動(ぴょりこだけ返ってくる)になってくれる。

www.elastic.co

まとめ

Elasticseachと仲良くなるために、これまで手探りで進めてきた過程で生まれた思い出(????)をいくつか切り取って紹介した。 僕とElasticsearchとの関係はまだまだ始まったばかり。もっともっとElasticsearchを知ってどんどん仲良くなっていこうと思う。

・・・とりあえず入門書位読んでみようかなと思う。

*1:ふわふわしている。

*2:そういうのじゃなければ何万と食わせることができる。