布団の中にいたい

Androidアプリ開発の勉強をしている傍らで、elasticsearchとかをいじってみたりしています。最近は数学の勉強が楽しくなってきました。

ElasticsearchのWildcardQueryを使った部分一致検索

ElasticsearchでMySQL的なLIKE検索をやろうとしてちょっとハマったのでメモ。

Elasticsearchで部分一致検索を実装するにはWildcardQueryを使います。WildcardQueryMySQLのLIKE文による検索に近く、ある程度同じようなことができます。

以下は簡単な例。 この場合だと、contentというプロパティで入力したクエリを含むものを検索結果として出力します。

{
    "query": {
        "bool": {
            "must": [
                {
                    "wildcard": {
                        "content": "*検索したいクエリ*"
                    }
                }
            ]
        }
    }
}

ここで若干ハマったのですが、wildcardで検索するクエリはindexされているものと比較されているようです。つまり、kuromoji_tokenizerなどを使って、contentをparseしていると、検索したいクエリと部分一致が取れず検索結果が0件という状態になります。とりあえずどうしていいか分からなかったので、部分一致用のプロパティを作って検索する際にはそこを参照するようにしてなんとか解決しました。

まとめ

elasticsearchでWildcardQueryを使って、MySQL的な部分一致検索ができました。wildcardで指定するためのプロパティを作らないといけなかった所で詰まりましたが、概ね解決してよかったです。

query stringが自由すぎてびっくりした話

Elasticsearchを使って実際に検索するときに便利なクエリがQueryStringQuerySimpleQueryStringQueryです。これらはqueryでfieldを指定したりAND・OR・NOTを指定できたりするのでかなり自由度が高いクエリです。

この2つのクエリ、使う分にはかなり便利なのですが、分かってないで使うと非常に危なさそうだったので、備忘録代わりに書きます。

SimpleQueryStringQueryとQueryStringQueryはquery_stringのパラメータとして、fieldsを指定することで、そのfieldsの中から検索をすることができるのですが、QueryStringの場合、queryに直接fieldと値を指定されてしまうと、その条件で検索をかけてしまいます。

以下のmappingでindexを作成したとします。 sampleというtypeでidとuser_idというpropertyを定義しています。propertyはともにkeywordです。

{
    "mappings": {
        "sample": {
            "properties": {
                "id": {
                    "type": "keyword"
                },
                "user_id": {
                    "type": "keyword"
                }
            }
        }
    }
}

上記のmappingのindexに以下のデータを入れているとします。

{ "id": "test1", "user_id": "user_id1"}
{ "id": "test2", "user_id": "user_id2"}
{ "id": "test3", "user_id": "user_id3"}

そして以下のクエリを投げると、まさかidがtest2のdocumentが引っこ抜けてしまいます。

GET sample/sample/_search
{
    "query": {
        "query_string": {
            "query": "id:test2",
            "fields": ["user_id"]
        }
    }
}

ちなみにSimpleQueryStringQueryの場合だと指定したfieldsから検索されるので検索結果は空で返ってきます。

まとめ

QueryStringQueryとSimpleQueryStringQueryはとても便利なのですが、私みたいによく分かっていない状態で使うと色々危ないので、無難に検索するのであれば、MultiMatchQueryを使うのが無難かもしれないです。もっと細かい検索(AND・OR・NOTなど)を使いたいのであれば、自前でquery builderを書いたほうがいいんですかね。

logstashのmonitoring apiを叩くためのgo用ライブラリを作った

logstashを動かした時にどうやって監視しようと思うと、まぁほぼほぼx-packを使ってkibanaで監視すると思います。 monitoringに関してはx-packもただで使えますしね。

そんな中でkibanaを使わないで確認したいと思い至ったので、monitoring apiを叩くgo用ライブラリを作ってみました。 monitoring apiは実験的なものみたいなので、いつ無くなるか分からないですが、現状であればこれで十分だと思います。

github.com

Monitoring Logstashのページに記載されている以下の4つのAPIを実装しています。

  • Node Info API
  • Plugins Info API
  • Node Stats API
  • Hot Threads API

基本的なapi clientの作成の仕方については、以下の記事を参考にさせていただきました。ありがとうございました。

GolangでAPI Clientを実装する | SOTA

構成自体はelasticsearchのapi clientであるelasticを参考にしています。 github.com

一応apiを一通り実装してはいるもののテストが致命的に少ないので若干動作が不安です。なので使ってみたいと思う方は適当になおしてプルリクを投げていただけると嬉しいです。

logstashの設定ファイルが正しいかを調べる

logstashの設定ファイルを色々書いていると、その設定ファイルがきちんと動くかを確認するために試す必要が出てきます。

単純に動かすだけなら以下のコマンドでもいいのだけれど、試す前に括弧が抜けてるなどの設定ファイルの文法が間違ってることが間々あります(少なくとも私は)

$ /usr/share/logstash/bin/logstash -f "config file"

いい方法は無いかと、logstashのhelpを眺めていたらファイルの文法チェックをしてくれるオプションがあることが分かりました。 コマンドは以下。

$ /usr/share/logstash/bin/logstash --config.test_and_exit -f "config file"

–config.test_and_exitを付加すると設定ファイルの文法をチェックして終了します。

これで毎回動かさなくてよくていいですね。

elasticsearchでanalyzerを試すコマンドラインツールを作った

elasticsearchでanalyzerを試す際に毎回/_analyzeを叩いて検証するのもだんだん面倒臭くなってきたので、さっくり試すためのコマンドラインツールを作りました。

github.com

とりあえず試せることを目指して作ったので機能はかなり少なく、analyze apiのfilterとchar filterは使えません。

README.mdにありますが、使い方は以下。

$ es-analyzer --host http://localhost:9200 --analyzer standard --query "This is a pen."
token   start_offset    end_offset  type    position
this    0   4   <ALPHANUM>    0
is  5   7   <ALPHANUM>    1
a   8   9   <ALPHANUM>    2
pen 10  13  <ALPHANUM>    3

実装はかなりシンプルでフラグの処理に標準パッケージのflag、elasticsearchのリクエストにはolivere/elasticを使っています。

github.com

filterとchar filterは欲しくなったら実装します。あとはamazon esで利用する場合に認証をどうするかとかですかね。

cerebroで毎回hostを入力しなくていいようにする

概要

このところ、elasticsearchの管理をするときにcerebroを使っています。対してデータが入っているわけではないですが、何かしらイベントが発火するとデータが増えていくのを見ているのが楽しいです。 リポジトリは以下。

github.com

さて、cerebroを色々使って便利だと思っていたのですが、毎回参照したホストのURLを入力しなければならないことに辟易していました。入力した履歴からサジェストされるとしても、それが消えると大変面倒です。どうにかいい方法はないものかとcerebroのリポジトリを眺めていると簡単に解決する方法があることが分かりました。

方法

cerebroはそれ自身の設定ファイルを配置する場所としてconfディレクトリを持っています。その中のapplication.confに表示したいhostを記述すれば毎回そのhostを表示してくれます。 記述する場所は以下。

hostは参照したいhostのurlで、nameは文字通りhostの名前を書けばいいです。以下では、hostにとりあえずlocalで動かしているelasticsearchを、nameはざっくりlocal elasticsearchにしています。

# A list of known hosts
hosts = [
  {
    host = "http://localhost:9200"
    name = "local elasticsearch"
  }
]

設定ファイルを編集した状態でcerebroを起動すると、以下のような表示になります。 f:id:asahima_194h:20170901230222p:plain

HOSTSとして先ほど指定したhostが追加されていますね。これで毎回hostのurlを記述しないといけない辛さから解放されます。

まとめ

今回はcerebroで指定したホストを選択できるようにしました。適当に使ってた手前なにも言えないですが、ちゃんとDocumentを読めばもっと便利に使えそうなので色々やってみようと思います。

go test で特定のテストのみを動かす

このところ、自分で使うようのコマンドラインツールを作っているのですが、テストが多くなってきたこととテストに他のソフトウェアを含んでいる影響で激烈にテストが遅くなってきていて若干不満だったのですが、特定のテストだけ実行する方法があったのでメモ。

方法は単純、テスト時に -r で実行したいテスト名をくっつけるだけ。 例として、Sampleという文字列がtest名に含まれたテストを実行した場合は以下

go test ./... -run Sample

サブテストなども指定できるので色々便利そう。詳細は以下ページより

testing - The Go Programming Language