全文検索エンジン「Elasticsearch」を調べて使ってみた色々まとめ

    url

    こんにちは、AWSではcodedeployが好きな中村です。

    IT業界はドッグイヤーと言われて久しいですが、技術の進歩は目まぐるしく進んでいます。

    それに伴い、世の中が求めるWebサービス・スマホアプリのスピード感は日々増しています。

    ページを表示するのに2秒以上かけてはいけない、、0.1秒表示速度が遅くなるとxxx件のユーザーが離脱する。。など、いろいろな通説が出てきているほどです。

    今回はそんな世の中が求めるWebサービスの表示スピードを劇的に速くできるサービス「Elastichsearch」について調べてみました。

     

    このサービスはFacebookGithubでも採用されているサービスですので、知っておいて損はないです。

    ではまず、ElasicSearchとはどんなサービスでしょうか?

    ■Elasticsearchとは

    ・概要

    Elasticsearch(エラスティックサーチ)とは、Elastic社が提供する「Lucene」ベースのオープンソース全文検索エンジンです。
    なお全文検索エンジンとは、大量にあるドキュメントデータの中から、目的のワードを含むドキュメントデータを検索するための仕組みです。

    ・MySQLなどのRDBMSとの違いや特徴

    特徴として、MySQL(RDBMS) 、Redshift(データウェアハウス)、DynamoDB(NoSQL)などと比べると、複雑な検索、高速に実行などが実現可能です。
    キーワードとして以下があります。
    【スケーラブル】
    超大規模なシステムでも利用できます。理由としてクラスタ構成(複数のコンピュータを連結し、1台のコンピュータとして振る舞う)が前提で作られているからです。既存データの分散/レプリカなどが自動で実行できたりするため、Hadoopとの親和性も高いです。
    【スキーマレス】
    データ構造が非常に柔軟性に富んでいます。JSON 形式のデータを受けていおり、様々なデータ構造(ネスト形式など含む)でもインデックスができたり、スキーマ(データマッピング)定義もなしで、データ投入などもできます。
    【マルチテナント】
    様々なサービスで自由に横断して検索・分析が可能です。1つのクラスタに複数のIndex(データのまとまり) が作成でき、そこに対して簡単かつ高速に検索処理ができます。対象ワードの出現頻度(スコア)を使った検索ができることや、「Kibana」と連携すると簡単にデータ分析もできます。

    ■Elasticsearchで覚えておくべきキーワード

    MySQLと比較しながらElasticsearchの覚えておくべきキーワードをまとめます。

    ・Cluster(クラスタ)とNode(ノード)

    ClusterとはNodeの集合体です。
    Nodeとはサーバーと同じ概念のレベルのもので、1台のサーバーに1Node用意します。
    トラフィックが増加した場合は、Nodeを増やすことで、処理速度の分散ができるような仕組みになっています。

    ・Index(インデックス)

    RDBのDatabaseの概念レベルに該当します。
    1つのClusterに複数のIndexが作成できます。

    ・Type(タイプ)

    RDBのTableの概念レベルに該当します。
    1つのIndexに複数のTypeが作成できます。

    ・Document(ドキュメント)

    RDBのRowの概念レベルに該当します。
    idをキーにして個々のデータを管理します。

    ・Shard(シャード)

    RAIDで構成されたハードディスクと似た仕組みになります。
    1つのindexを作成すると、合わせてShadが複数作成されます。
    ShardはPrimary(master)とReplicaで構成されており、1Nodeには1shard配置されます。
    例えばPrimaryがすでに存在するShardには同じNodeにReplicaは存在できず、別のNodeに配置されます。

    ■Elasticsearchを触ってみる

    では実際にElasticsearchを触ってみます。
    なお、全てMacのローカル環境で実施しています。

    ・nodeも必要なためインストール

    使うにはNodeが必要です。nodebrewをインストール、ディレクトリがないエラーが発生したため、これも作成し、パスを通します。
    ※xxxはユーザー名
    brew install nodebrew
    mkdir /Users/xxxxx/.nodebrew/
    mkdir /Users/xxx/.nodebrew/src
    nodebrew install-binary latest
    export PATH=$PATH:/Users/tnakamura/.nodebrew/current/bin

    ・elastic searchのインストール

    ・インストールできるバージョンの確認し、バージョン2.4をインストール、実行
    brew search elasticsearch
    brew install elasticsearch@2.4
    cd /usr/local/Cellar/elasticsearch@2.4/2.4.4/bin/
    ./elasticsearch

    以下のipで起動されます
    127.0.0.1:9300
    これで準備完了

    ・データの投入や検索

    以下のようなコマンドで状態の確認ができます。

    curl 127.0.0.1:9200 #バージョンの概要
    curl 127.0.0.1:9200/_cat/health?v #クラスターの状態を確認
    curl 127.0.0.1:9200/_cat/indices?v #インデックスの状態を確認

    では実際にデータを投入してみます。

    #indexの作成
    curl 127.0.0.1:9200/customer -X PUT
    #sheardsのreplicaが不要なので削除する
    curl -H 'Content-Type: application/json' -X PUT -d '{"index":{"number_of_replicas": 0}}' 127.0.0.1:9200/customer/_settings
    #TypeとDocumentを作成
    curl -H 'Content-Type: application/json' -X PUT -d '{"name”:”test”}’ 127.0.0.1:9200/customer/external/1
    #投入結果を確認
    curl 127.0.0.1:9200/customer/external/1 | python -mjson.tool
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 147 100 147 0 0 51006 0 --:--:-- --:--:-- --:--:-- 73500
    {
    "_id": "1",
    "_index": "customer",
    "_source": {
    "day": "2017-11-12",
    "name": "test",
    "timeFieldName": "day"
    },
    "_type": "external",
    "_version": 1,
    "found": true
    }

    データ投入ができました。

    他にも以下のようなコマンドで操作ができます。

    #paramsで指定の文字検索
    curl -H 'Content-Type: application/json' -X GET -d '{ "id": "template01", "params": { "firstname": "Tammy" }}' 127.0.0.1:9200/_search/template
    #_updatでのデータ更新
    curl -H 'Content-Type: application/json' -X POST -d '{"doc":{"day":"2017-11-12"}}' 127.0.0.1:9200/customer/external/1/_update

    ■ElasticsearchとMySQLのDBを連携させる

    ElasticsearchはMySQLのDBを連携させ、データ検索もできます。
    MySQLで検索速度を改善したい。そんな時は連動してElasticsearchを使うことでパフォーマンス向上ができます。
    連動させるサービスとして、以下を取得します。(JDBCを使っている連携ツールです)
    ・サイト
    https://github.com/jprante/elasticsearch-jdbc
    ここからelasticsearch-jdbcの取得をします。
    ※elasticsearchとのバージョンが連動していないといけなく、JDBCに合わせたelasticsearchをこの後入れ直しました。
    なお、ローカルでMySQLの環境は事前に用意していて、対象のテーブルは1万件程度のデータが入っています。
    ここからデータをMySQL→Elasticsearchへ投入するスクリプトを実行します。

    wget http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.4.1/elasticsearch-jdbc-2.3.4.1-dist.zip
    unzip elasticsearch-jdbc-1.7.1.0-dist.zip
    cd elasticsearch-jdbc-1.7.1.0/lib
    cp mysql-delete-document.sh mysql-oreore.sh
    #環境に合わせて取得情報を変更します
    vi mysql-oreore.sh
    -----
    "jdbc" : {
    "url" : "jdbc:mysql://localhost:3306/[DB名]”,
    "user" : "root",
    "password" : "",
    "sql" : "select id as _id, xxxx, xxxx,xxxx from xxxx”
    }
    -----
    ./mysql-oreore.sh

    ※注意として’as _id’の記載がないとデータが意図しないidで振られてしまいます。
    データ件数はかなりありましたが、1秒程度で処理が終わりました。
    この処理でMySQL→Elasticsearchへのデータ投入が完了です。

    実行結果を確認します。
    #'jdbc'indexデータを取得
    curl -XGET 'http://localhost:9200/jdbc/_search?pretty=true'
    #jdbcからindexのデータ件数を取得
    curl -H 'Content-Type: application/json' -X GET -d '{"query":{"match_all":{}},"size":0}' http://localhost:9200/jdbc/_search?pretty=true | python -mjson.tool
    #結果
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 232 100 197 100 35 2605 462 --:--:-- --:--:-- --:--:-- 2626
    {
    "_shards": {
    "failed": 0,
    "successful": 5,
    "total": 5
    },
    "hits": {
    "hits": [],
    "max_score": 0.0,
    "total": 16295
    },
    "timed_out": false,
    "took": 31
    }

    “total”: 16295件のデータが投入されていること確認できました。

    ■ElasticsearchとMySQLの実行速度を比較する

    Apache benchを使ってMySQLへのデータ取得との速度を比較します。

    まずは適当にMySQLヘの接続、jsonでのレスポンスをするphpファイルを作り、AB実行します。
    # ABテスト
    ab -n 100 -c 1 'http://localhost:8000/testDBget.php'
    # 結果(抜粋)
    Requests per second: 1.62 [#/sec] (mean)
    Time per request: 618.267 [ms] (mean)
    Time per request: 618.267 [ms] (mean, across all concurrent requests)
    Transfer rate: 322.72 [Kbytes/sec] received

    次にElasticsearchを実行します。
    # ABテスト
    ab -n 100 -c 1 'http://localhost:9200/jdbc/_search?pretty=true'
    # 結果(抜粋)
    Requests per second: 1222.40 [#/sec] (mean)
    Time per request: 0.818 [ms] (mean)
    Time per request: 0.818 [ms] (mean, across all concurrent requests)
    Transfer rate: 45766.15 [Kbytes/sec] received

    Time per request(同時実行したリクエストの平均処理時間)が、
    ・MySQL:618.267ms
    ・Elasticsearch:0.818ms
    その差100倍以上、圧倒的に処理速度が速いです。
    当然環境に依存する部分があったりとかで正確な数字かは微妙ですが、間違いなくパフォーマンスは高いです。

    ■kibana(sense)を使いデータをビジュアライズ

    kibana(sense)を使ってデータをビジュアライズ化します。
    #kibana、senseのインストール
    wget https://download.elastic.co/kibana/kibana/kibana-4.3.1-darwin-x64.tar.gz
    bin/kibana plugin --install elastic/sense
    #kibanaの実行
    kibana-4.3.1-darwin-x64/bin/kibana

    ※バージョンが連動していないと動かないため、elasticsearchとのバージョン関係は注意が必要
    これは適当にいじっただけですが、それっぽいグラフが出せました。

    スクリーンショット 2017-02-05 18.38.07

    まとめ

    まだまだ奥が深く、調整もいろいろ必要そうですが、導入すると非常に破壊力のあるツールになると感じました。
    特に一番驚いたのは、その処理速度。
    大規模なシステムになった場合でもこの検索エンジンを使えば問題なくさばけそうです。
    今後もぜひ活用していきたいです。

    以下参考にさせていただきました。

    ‘http://dev.classmethod.jp/server-side/elasticsearch-getting-started-05/
    ‘http://dev.classmethod.jp/server-side/elasticsearch-getting-started-06/
    ‘http://dev.classmethod.jp/server-side/elasticsearch-getting-started-07/
    ‘http://dev.classmethod.jp/server-side/elasticsearch-getting-started-08/
    ‘https://www.ossnews.jp/oss_info/Elasticsearch
    ‘https://www.idcf.jp/words/schema.html


    関連記事

    • 会話、対話、交渉(折衝)

      どうも。 伊藤です。 気難しいタイトルですが・・・要はコミュニケーションについてです。 私は大学を卒業してから14年間一貫して制作者、作り手側の立場として仕事を続けてきたため、創造力、企画力、制作力、技術力など作り手としての能力を磨き、日々アンテナを張り生活をしてきました。 ただし、実は最も重要な能力は「コミュニケーション能力」だと思っています。(当然ながら、作り手としての能力も兼ね備えている事が前提です。) モノを作る時、ほとんどの場合、誰かのために作ります。 自分のためだけに作るのであればコミュニケーションは不要かも知れませんが、自分以外の誰かのためにモノを作るのであれば、相手が本当に喜ぶモノ、必要としているモノを作るべきです。そしてそこで重要となるのがコミュニケーション能力です。

      コミュニケーション能力って?

       コミュニケーション能力を大別すると、「話す力」と「聴く力」になると思います。共に重要な力であり、どちらか一方が欠けてしまうとコミュニケーションに問題が生じますが、私の考えでは「話す力」 < 「聴く力」だと思っています。そして、タイトルにもあるように、状況や目的に応じてコミュニケーションの方法(会話、対話、交渉)を使い分ける力も必要です。  冗談を言って場を盛り上げたりする能力があれば、コミュケーション能力が高いという訳ではないので注意が必要です。状況に応じて必要な時に冗談を言い盛り上げているのであればそれはコミュニケーション能力の一つと言えますが、あくまでも一手段でしかありません。  当たり前の事しか書いていませんが、コミュニケーションに関わる様々な書籍にあるような細かなテクニックはさておき、まずは「話す力」、「聴く力」、「状況や目的に応じた使い分け」を意識するだけでもコミュニケーション能力は高まると思います。

      話す力

       アナウンサーのように噛まずに流暢に話しをしたり、ダウンタウンの松ちゃんのようにオチを入れて話しをする能力は、並大抵の努力では身に付きません。お笑い芸人など話しが上手い人を見ると産まれ持っての素養や能力のように感じる人も居ると思いますが、私は基本的には努力や勉強をした結果と考えています(松ちゃんは産まれもっての天才かもですが)。そして、さすがにアナウンサーや芸人などコミュニケーションのプロを目指すのは敷居が高すぎるので、まずは以下のような簡単な所から始めていく事をお薦めします。  ちなみに、会社のブログのため・・・私生活ではなく仕事、且つお客様とのコミュニケーションにフォーカスしています。 ・出だしを否定(でも、ただ、~ですが)から始めない。 ・相手の言葉に理解、興味を示した上で話す。 ・相手の性格や立場を意識して話す。 ・相手を喜ばせたいと思いながら話す。 ・熱心に真剣に話す。 ・自信を持った態度で話す。 ・自信が無い(曖昧、責任が取れない)事は話さない。 ・相手の目や仕草(反応)を見て話す。 ・自分の表情に気を付けて話す。 ・相手が話しをしたく(続けたく)なるように話す。  特別な勉強は必要なく、意識することで簡単に始められるお薦めのトピックス10選です。あくまでも自論のため、ご参考までに・・・

      聴く力

       話す力同様に、聖徳太子のように何人もの話しを同時に聴き分ける力は必要ありません。こちらも同様に意識することで簡単に始められるお薦めのトピックス10選をご紹介します。 ・うなずき、あいづちをしながら聴く。 ・相手の話しを遮らない。 ・相手の目や仕草を見て話しを聴く。 ・自分の表情(微笑みなど)や仕草(反応)に気を付けて話しを聴く。(話しやすい環境を作る) ・内容に興味を持って(または興味を持っている風に)話しを聴く。 ・言葉や文字に捉われず、相手が伝えたい内容に目的を絞り話しを聴く。 ・相手がどのような気持ちで話しをしているのかを意識して話しを聴く。 ・相手の性格を意識して(話し相手がどういう人なのか興味を持って)話しを聴く。 ・相手を尊重して話しを聴く。 ・素直な気持ちになり話しを聴く。  コミュニケーションは相手が居て初めて成立します。という事は、話しを聴く力は非常に重要であり、ここを怠るとどれだけ話す力があってもそのコミュニケーションからは信頼や安心は生まれません。重要だと書きながら私自身もできていない事が多いですが、とにかく相手が話し易い環境を作り、相手の話しを引き出し、そしてそこから安心や信頼を築き上げる対応が重要だと思っています。

      状況や目的に応じた使い分け

       上記の話す力、聴く力は仕事上での「対話や交渉」においてのトピックスに偏っています。日常生活における家族、恋人、友人、同僚などとの「会話」であれば、必要のない項目もあり、逆に「会話」になると別途必要となるトピックスもあります。今回は仕事におけるコミュニケーションにフォーカスしているため、「対話」と「交渉」の違いについて書きたいと思います。  言葉の意味や解釈の違いはあくまでも私の自論のため、間違っていたらすいません。大切なのは、仕事上でのコミュニケーションも状況により手法を使い分け、しっかりとした準備と主張が重要という点です。プレゼンなどの資料を用意する時や成果物を納品する時は誰でも準備を怠りませんが、方やそれ以外のコミュニケーション(特に対話)についてはしっかりとした準備をせず、相手の目的を引き出せていない、目的を相手に伝えきれていない、その場しのぎ、と感じるケースが多いです。  私の解釈では、対話は「お互いを理解、信頼し合うために本音で話し合う事」で、交渉は「利害関係のある両者が互いの要求を主張し、両者の主張が最大になる妥協点を目指して合意形成する事」です。  対話や交渉というキーワードでも多数の書籍が出版されていますが、私が言いたい事は以下です。 ・対話をする前に、相手を知るための準備、自分を理解してもらうための準備をしておく。 ・信頼を得るには、会社や商品とは別に自分自身も売り込む(理解、信頼してもらう)必要がある。 ・対話をしないと信頼は生まれない。(交渉だけしていても信頼は生まれない) ・対話をできていないと交渉が上手くいかない。(両者の主張の最大の妥協点に落ち着かない) ・交渉は両者の主張が必要である。(相手の主張に合わせる事が交渉ではない) ・交渉は両者がWin-Winでないとその後継続しない。(両者の妥協点が一致しないと、その後の関係に繋がらない)  こんな偉そうな事を書きましたが、定期的に妻から「俺は!俺は!って煩いな・・・」と言われています。主張ばかりでは駄目ですね。気を付けます! ではでは。
      2018/02/22 技術 / デザイン / 制作 日常 / プライベート