elasticsearch 5.0.0-alpha4 をみると datatype に IPv6 を含む IP 型ができている https://www.elastic.co/guide/en/elasticsearch/reference/master/ip.html
An ip field can index/store either IPv4 or IPv6 addresses.
試してみたい。 IPv6 もよく知らないので、ちょっと触ってみたい。せっかくなので Packetbeats も試してみたい。
やってみたら、 IPv6 を使うときは ip 型の stored を有効にしたほうが良さそうということがわかった。
Elasticsearch + kibana
とりあえず環境をつくる。
% docker pull elasticsearch:5.0.0-alpha4
% docker run -d --name es2 elasticsearch:5.0.0-alpha4
メモリ確保できないといわれた
{"log":"Exception in thread \"main\" java.lang.RuntimeException: bootstrap checks failed\n","stream":"stderr","time":"2016-07-10T06:56:11.405356902Z"}
{"log":"initial heap size [268435456] not equal to maximum heap size [2147483648]; this can cause resize pauses and prevents mlockall from locking the entire heap\n","stream":"stderr","time":"2016-07-10T06:56:11.405443037Z"}
https://discuss.elastic.co/t/initial-heap-size-not-equal-to-maximum-heap-size/50499 を参考にして
ES_HEAP_SIZE を変更しようとしたら、 ES_JAVA_OPTS を編集してと言われた。
% docker run -it --rm -e ES_HEAP_SIZE='256m' --name es03 elasticsearch:5.0.0-alpha4
Error: encountered environment variables that are no longer supported
Use jvm.options or ES_JAVA_OPTS to configure the JVM
ES_HEAP_SIZE=256m: set -Xms256m and -Xmx256m in jvm.options or add "-Xms256m -Xmx256m" to ES_JAVA_OPTS
また、おこられた
% docker run -it --rm -e ES_JAVA_OPTS='-256m -256m' --name es03 elasticsearch:5.0.0-alpha4
max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
vm.max_map_count はプロセスが利用可能なメモリマップの最大値らしい。
少なくとも 262144 にして欲しいそうなので変える。
sysctl で書き換える。
sudo sysctl -w vm.max_map_count=262144
無事立ち上がった。
docker run -it --rm -e ES_JAVA_OPTS='-Xms256m -Xmx256m' --name es03 elasticsearch:5.0.0-alpha4
kibana も新しいのにしてみた。
docker run -it --rm --link es03:elasticsearch --name kibana02 kibana:5.0.0-alpha4
kibana 開いてみたら自分が見慣れていた色と違う色使いの画面が出てきて戸惑った。

Upload CSV とか書いてあった。 1GB までの CSV ならアップロードできるみたい。

気になったので少し脱線してやってみた。 統計庁から適当な csv 持ってきていれてみた。 http://www.e-stat.go.jp/SG1/estat/List.do?bid=000001033705&cycode=0

先頭行がフィールド名として扱われた。デリミタはタブ、スペース、セミコロン、パイプも指定できる。 適当に整形した。

各フィールドの型は決められるみたいだった。
事前に時間を表すフィールドは date 型に変換できるように整形したほうが良さそうだった。
今回は 199901 を 1999-01 に事前に修正すればよかった。
インデックス名もここで決められた。

無事アップロードできた。

飲み物の消費者物価指数推移とかが作れた。
どうでも良いことだが、物価指数は基準の月を 100 とした時の、
比較を表しているものらしかった。
packetbeats
まずはダッシュボードの準備。 https://github.com/elastic/beats-dashboards 指定する IP は ES の IP なので注意。
% ./load.sh -url "http://172.17.0.2:9200"
いくつか kibana のダッシュボードが増える。 web と db については、詳細に見られそうだった。
packetbeats そのものをインストールする。ここにしたがってインストールした。 https://www.elastic.co/guide/en/beats/packetbeat/current/packetbeat-installation.html
ES にテンプレートを適用した。
% curl -XPUT 'http://172.17.0.2:9200/_template/packetbeat' -d@packetbeat.template.json
packetbeat.yml が必要らしいので書く。インデックス名は packetbeat にしないと、
多分テンプレートと、ダッシュボードがうまく使えない。
hosts: ["172.17.0.2:9200"]
index: "packetbeat"
template:
path: "packetbeat.template.json"
コンフィグテストして実行した。
% sudo packetbeat -configtest -e ./
% sudo packetbeat
es にちゃんと溜まった。
ES に残っている結果をみてみた
kibana からドキュメントを見たところ、 ip のフィールドの type が string になっていた。 v1.2 を入れていたが packetbeats 用のテンプレートで特に指定されていないのでそうなっている。 https://github.com/elastic/beats/blob/1.2/packetbeat/etc/packetbeat.template.json
master ブランチをみたら keyword となっていた。 ip ではないので、やろうと思っていたことができない。
https://github.com/elastic/beats/blob/master/packetbeat/packetbeat.template.json#L910-L913
よくよく考えたら現行バージョンの ip 型は IPv6 に対応していないので、この型になっているのは正しい。
試してみたいので IP が入るところを ip に適当に変換して適用してみた。 ingest API でも設定できそうだが、 beats で送信するときにうまく設定する方法がわからなかったので、やらなかった。
% curl -XPUT 'http://172.17.0.2:9200/_template/packetbeat' -d@packetbeat-iptest.template.json
% curl -XDELETE 'http://172.17.0.2:9200/packetbeat-*'
% sudo packetbeat
ip 型を使うと良い所 IPv4
IPv4 では range の検索はできる。
POST packetbeat-*/_search
{
"query": {
"range": {
"client_ip": {
"from": "127.0.0.1",
"to": "127.255.255.255"
}
}
}
}
IPv4 で CIDR の検索もできる(v2.2.0 以降らしい)。
POST packetbeat-*/_search
{
"query": {
"term": {
"client_ip": "127.0.0.0/8"
}
}
}
IPv6 を入れた時のこと
packetbeats からやるのが面倒になったので試しにデータを入れてみる。
curl -XPOST http://172.17.0.2:9200/iptest -d '{
"mappings" : {
"testtype" : {
"properties" : {
"ip" : { "type" : "ip" }
}
}
}
}'
入れた順番でソートしたいので作成時間のフィールドを追加。 _datetime は5系ではなくなって、
ingest API で設定するようになったらしい。
https://www.elastic.co/guide/en/elasticsearch/reference/master/accessing-data-in-pipelines.html#accessing-ingest-metadata
現在のところ mapping とかで pipeline は指定できないので、ドキュメント作成時に指定するか、 reindex しないといけないらしい。
curl -XPUT 'http://172.17.0.2:9200/_ingest/pipeline/add-received-pipeline' -d'{
"description": "add received time",
"processors": [
{
"set": {
"field": "received",
"value": "{{ _ingest.timestamp }}"
}
}
]
}'
入れるデータは http://www.ietf.org/rfc/rfc5952.txt を参考にした。
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:001" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:01" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:0:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8::aaaa:0:0:1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:0:0:aaaa::1" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa" }'
curl -XPOST 'http://172.17.0.2:9200/iptest/testtype/?pipeline=add-received-pipeline' -d '{ "ip" : "::0" }'
中に入っているデータは、同じ IP でも入れた時と同じ形式で入っていた。
% curl -s -XPOST http://172.17.0.2:9200/iptest/_search -d'{ "size": 100, "sort": "received" }' | jq ".hits.hits[]._source.ip"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"
"2001:db8:aaaa:bbbb:cccc:dddd::1"
"2001:db8:aaaa:bbbb:cccc:dddd:0:1"
"2001:db8:0:0:0::1"
"2001:db8:0:0::1"
"2001:db8:0::1"
"2001:db8::1"
"2001:db8::aaaa:0:0:1"
"2001:db8:0:0:aaaa::1"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa"
検索してみた。表記方法が異なってもちゃんと検索されていた。
curl -s -XPOST http://172.17.0.2:9200/iptest/_search -d'{
"query": {
"term": {
"ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
}
}
}
' | jq ".hits.hits[]._source.ip"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"
中に入っている情報は 128bit なはずなので調べる。 (補足)5 系から field -> stored_field, fielddata_field -> docvalue_field に変更されているようだが、 alpha4 の時点では、一度元に戻されていたため、 fielddata_fields を指定しないと動かなかった。5系リリース時点では、 docvalue_field 指定が正しくなっていそう。
% curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
"query": {
"term": {
"ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
}
},
"fielddata_fields" : ["ip"]
}
' | jq ".hits.hits[] | .fields.ip[0], ._source.ip" | paste -d, - -
フィールドとして変換された結果は同じものとして、入っているみたいだった。 フィールドのほうは読めない。
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"
" \u0001\r¸ªª»»̌ݝ\u0001","2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
入っている内容はよくわからないし、バイト数も多い。
% curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
"query": {
"term": {
"ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
}
},
"fielddata_fields" : ["ip"]
}
' | jq -r ".hits.hits[0] | .fields.ip[0]" | hexdump -C -s 1
00000001 01 0d c2 b8 c2 aa c2 aa c2 bb c2 bb cc 8c dd 9d |................|
00000011 ee ae 80 01 0a |.....|
00000016
いろいろ調べてたら doc_value として持っていたら良さそうだった。 https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/search/DocValueFormat.java#L296
ip を stored にしてみた。
curl -XPOST http://172.17.0.2:9200/iptest -d '{
"mappings" : {
"testtype" : {
"properties" : {
"ip" : { "type" : "ip", "stored": true }
}
}
}
}'
検索してみる。
curl -s -XGET http://172.17.0.2:9200/iptest/_search -d'{
"query": {
"term": {
"ip": "2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"
}
},
"fields" : ["ip"]
}
' | jq ".hits.hits[] | .fields.ip[0], ._source.ip" | paste -d, - -
ちゃんと見える状態で入ってきた。 stored にすると source を変換した値が入ることがあるようだった。知らなかった。
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",null
kibana でも統一されたフォーマットで表示されるようになった。

感想
- ip 型を使って、 IPv6 の検索結果のフォーマットを統一したいときは、 stored を true にしたほうが良い。
- ingests API の pipeline をデフォルトで通すようにしたいけど、 mapping とかで設定できないのでどう設定すればいいかわからなかった
- test-kitchen を途中で見かけたけど便利そうだった
みたところ
- https://docs.oracle.com/javase/jp/6/api/java/net/Inet6Address.html
- https://github.com/apache/lucene-solr/blob/91fd163112b9a433d3e1f578d5c8a9cfbd9dce2f/lucene/sandbox/src/java/org/apache/lucene/document/InetAddressPoint.java
- https://github.com/elastic/elasticsearch/blob/master/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java