Elasticsearch 5.0.0-alpha1 が公開されたので早速使ってみた

Elasticsearch-Logo-Color-V

こんにちは!Pairsの開発を担当している小島です。

今年の初めにElastic社から Elasticsearch, kibana, beats, logstash の各プロダクトがElastic Stackとして1つのパッケージで提供される発表がありました。
それに伴い各プロダクトもそれぞれ新しいバージョンが出るそうです。
新しいバージョンにする理由のひとつとして、Elasticsearchはこれまで2.3系が最新バージョンとして提供されていましたが、Elastic Stackのパッケージで全てのプロダクトのバージョンを一律にするため、Elastic Stackで提供されるバージョンは5.0系になるということです。
上記の発表はまだ開発段階のものですが、それぞれのプロダクトのalpha版が公開されています。(※注意:プロダクション環境での使用は推奨されていません)

Pairsで提供している機能の一部や、サーバーのログコレクターとしてElasticsearchを使用しているので、新しい機能や向上された性能に期待が高まるところです。

Elasticsearch 5.0.0-alpha1

インストール

インストール・起動については今まで提供されていたバージョンと変わりないようです。

以下のページからアーカイブをダウンロードして任意のディレクトリに展開し、実行ファイルから起動します。
https://www.elastic.co/downloads/past-releases/elasticsearch-5-0-0-alpha1

Elasticsearchの起動

実行ファイルは展開したディレクトリの中に /bin ディレクトリがあるので、そちらから起動します。

$ ./path/to/elasticsearch/bin/elasticsearch

※ 5.0.0-alpha1を使用するにはJava8が必要です。

デフォルトの設定ではport番号9200で起動しているはずなので、起動している確認してみましょう。

$ curl -XGET "http://localhost:9200/"
{
  "name" : "Canasta",
  "cluster_name" : "elasticsearch",
  "version" : {
    "number" : "5.0.0-alpha1",
    "build_hash" : "7d4ed5b",
    "build_date" : "2016-04-04T10:39:25.841Z",
    "build_snapshot" : false,
    "lucene_version" : "6.0.0"
  },
  "tagline" : "You Know, for Search"
}

Ingest Node

今回の新機能で一番気になっていた機能がこの Ingest Node です。

Ingest Nodeは「データをインデクシングする際に事前にデータを加工する処理を定義」することができる機能です。
これまでデータ送信時にクライアント側やPluginで処理していたことや、エージェントからElasticsearchへとデータを送る前に別の所で加工していたような処理がElasticsearch側で定義・変更できるようになるので、この機能をうまく扱うことができればデータの管理が楽になりそうです。

使い方

Ingest APIというAPIを使用してPipeLine(処理)を追加・編集します。
Simulate Pipeline APIを使用することで、処理とドキュメントから生成されるドキュメントを確認することもできます。

リクエスト

POST _ingest/pipeline/_simulate
{
  "pipeline" : // 処理部分
  {
    "description": "_description",
    "processors": [
      {
        "set" : { // ・・・・ (1)
          "field" : "field2",
          "value" : "_value"
        }
      },
      {
        "set": { // ・・・・ (2)
          "field": "created_at",
          "value": "{{_ingest.timestamp}}"
        }
      },
      {
        "set": { // ・・・・ (3)
          "field": "full_name",
          "value": "{{first_name}} {{last_name}}"
        }
      }
    ]
  },
  "docs": [ // ドキュメント部分
    {
      "_index": "index",
      "_type": "type",
      "_id": "id",
      "_source": {
        "foo": "bar",
        "first_name": "first",
        "last_name": "last"
      }
    },
    {
      "_index": "index",
      "_type": "type",
      "_id": "id",
      "_source": {
        "foo": "rab",
        "first_name": "hiroki",
        "last_name": "kojima"
      }
    }
  ]
}
(1) フィールドへの固定文字の追加
      {
        "set" : { // ・・・・ (1)
          "field" : "field2",
          "value" : "_value"
        }
      },

フィールド"field2"へ固定文字列"_value"をいれています。

(2) ドキュメント作成時間(タイムスタンプ)フィールドの追加
      {
        "set": { // ・・・・ (2)
          "field": "created_at",
          "value": "{{_ingest.timestamp}}"
        }
      },

フィールド"created_at"へタイムスタンプの値_ingest.timestampをいれています。
_ingestからtimestampのように環境変数がとれるようです。

(3) フィールド文字列の連結
      {
        "set": { // ・・・・ (3)
          "field": "full_name",
          "value": "{{first_name}} {{last_name}}"
        }
      }

フィールド"full_name"へフィールドfirst_name, last_nameを連結させた文字列を格納しています。
今回は文字列を扱っていますが、数値を扱う場合は演算なども可能です。

レスポンス

{
  "docs": [
    {
      "doc": {
        "_index": "index",
        "_id": "id",
        "_type": "type",
        "_source": {
          "full_name": "first last",
          "foo": "bar",
          "last_name": "last",
          "created_at": "2016-04-30T02:20:12.719+0000",
          "first_name": "first",
          "field2": "_value"
        },
        "_ingest": {
          "timestamp": "2016-04-30T02:20:12.719+0000"
        }
      }
    },
    {
      "doc": {
        "_index": "index",
        "_id": "id",
        "_type": "type",
        "_source": {
          "full_name": "hiroki kojima",
          "foo": "rab",
          "last_name": "kojima",
          "created_at": "2016-04-30T02:20:12.719+0000",
          "first_name": "hiroki",
          "field2": "_value"
        },
        "_ingest": {
          "timestamp": "2016-04-30T02:20:12.719+0000"
        }
      }
    }
  ]
}

ちゃんと処理が反映されていることが確認できました。
今回試した以外にも処理パターンはあるようなので、使い方次第でいろいろできそうです。

Painless Language

Painless LanguageはElasticsearchに組み込まれた新しいスクリプト言語で安全に実行できるよう設計されて作られています。

公式ドキュメントには以下の様な特徴が書いてありました。

Control flow: for loops, while loops, do/while loops, if/else
Fully Typed: all available types/methods described in Painless API
Arithmetic operators: multiplication *, division /, addition +, subtraction -, precedence ( )
Comparison operators: less than <, less than or equal to <=, greater than >, greater than or equal to >=, equal to ==, and not equal to !=, reference equals ===, reference not equals !==
Boolean operators: not !, and &&, or ||
Bitwise operators: shift left <<, shift right >>, unsigned shift >>>, and &, or |, xor ^, not ~
Shortcuts for list, map access using the dot . operator

簡単なスクリプトであれば以前のバージョンでも実行できましたが、JSのように記述ができるので詳細な処理が比較的簡単に書けるようになっています。

公式ドキュメントのサンプルを試してみます。

得点合計数を検索スコアとしてPainless Scriptで計算させる

GET /hockey-stats/_search
{
  "query": {
    "function_score": {
      "script_score": {
        "script": {
          "lang": "painless",
          "inline": "int total = 0; for (int i = 0; i < input.doc.goals.size(); ++i) { total += input.doc.goals[i]; } return total;"
        }
      }
    }
  }
}

得点合計数をフィールドとしてPainless Scriptで計算させる

GET /hockey-stats/_search
{
  "query": {
    "match_all": {}
  },
  "script_fields": {
    "total_goals": {
      "script": {
        "lang": "painless",
        "inline": "int total = 0; for (int i = 0; i < input.doc.goals.size(); ++i) { total += input.doc.goals[i]; } return total;"
      }
    }
  }
}

上記の例はどちらも配列で持っているパラメータ(得点数)の値をfor文で取り出し合計するだけのシンプルなリクエストですが、検索スコア・フィールドの計算でもスクリプトが簡単に書けるようになったことで、選択肢が増え、クライアント側の処理も簡略化することができるのはとても魅力的です。

ただ、ローカルで動かしているせいなのか少量のサンプルデータでも最初だけはレスポンスが返ってくるまで少し時間がかかるため、大量のデータで使用した際にどの程度処理に時間がかかるのかが少し懸念しております。

他にも、下記のようにフィールド単位でのアップデートをかけることも簡単に実現可能です。

POST /hockey-stats/player/1/_update
{
  "script": {
    "lang": "painless",
    "inline": "input.ctx._source.last = input.last input.ctx._source.nick = input.nick",
    "params": {
      "last": "gaudreau",
      "nick": "hockey"
    }
  }
}

その他の特徴

今回試した以外にも5.0.0-alpha版ではたくさんの気になる特徴があります。

参考:Elasticsearch 5.0.0-alpha1 released
参考:Elastic Stack 5.0.0 alpha 1 リリース

Lucene 6

Lucene 6がbaseになっており、いくつかの新しい機能、処理方法を受け継いでいます。(但し現在のElasticsearchでは未実装)
容量が半分になり、2倍速く、検索のパフォーマンスを25%増加される。

Instant Aggregations

誰もローディング中のプログレスバーは好きではないのを知っています。ですので、それらをなくすように頑張っています。Elasticsearchはより効率よく、よりクエリをキャッシュできるようになりました(特に、時系列インデックスに分割されたデータに対して)。

Text/Keyword to Replace Strings

文字列型のフィールドがText/Keywordの二種類が追加になり、Text型は文、Keywordは単語のように使い分けるようになります。
string型は5系でも使用はできますが、6系にアップデートと同時に削除される。

最後に

まだalpha版ということで、対応されていない機能やPluginがあり、まだまだ触りきれていないので正式版のリリースが非常にたのしみです!
私は開発中にsenseを利用する場面が多いため、早目にkibanaでsenseを扱えるようにしてもらえればと思っています!

今回はElasticsearchについての紹介でしたが、他のプロダクトでも新機能・改善が多くあるため、次の機会に他の機能の紹介させていただきます。

  • このエントリーをはてなブックマークに追加

エウレカでは、一緒に働いていただける方を絶賛募集中です。募集中の職種はこちらからご確認ください!皆様のエントリーをお待ちしております!

Recommend

UIデザインの悩みどころ「アイコンどうする問題」

まだルーティン作業で消耗しているの? ChatOpsでバックオフィス業務もまるごと自動化しています