PR TIMESデザイナー&エンジニアブログ BREAK TIMES

PR TIMES Developer Blog(デザイナー&エンジニアによる開発者ブログ)

PR TIMES Developer Blog

当ブログは下記URLに移転しました。
https://developers.prtimes.jp/

ElasticSearchとSQLクエリの取得比較検証 - 準備編

PR TIMESの落合です。

PR TIMESに、ElasticSearchを昨年導入しました。
ElasticSearchを使用する時に、条件設定をjsonで作成しますが、
複雑な条件式を作成すると、毎回「あれ?」ってなる事が多く、SQL比較した日本語での解説ページが、あまり無い為ので、自分で検証してみました!
kuromojiなどを使用すると、検証が分かりづらくなるので、今回は導入していません。

また、ElasticSearch、MySQLのインストールや、初期設定などに関しては、今回省略していますが、要望がありましたら、別途記事で書き残していこうと思います。

まず、今回の目的としては、ElasticSearchの検証環境を整えて、簡単なクエリができる所まで解説したいと思います。

ElasticSearchの検証データを作成する。

まず、ElasticSearchにindexを作成する必要があります。
今回は以下のようなindexを作成しました。

{
    "mappings": {
        "contents": {
            "_source": {
                "enabled": true
            },
            "properties": {
                "id": {
                    "type": "integer",
                    "index": "not_analyzed"
                },
                "title": {
                    "type": "string",
                    "index": "not_analyzed"
                },
                "price": {
                    "type": "integer",
                    "index": "not_analyzed"
                },
                "flag_a": {
                    "type": "integer",
                    "index": "not_analyzed"
                },
                "flag_b": {
                    "type": "integer",
                    "index": "not_analyzed"
                },
                "flag_c": {
                    "type": "integer",
                    "index": "not_analyzed"
                }
            }
        }
    }
}

データに関しては、検証結果が分かりやすい状態にしたかったので、以下のデータを挿入しています。

  {"id": 1,"title": "マイクロサービスアーキテクチャ","price": 3672,"flag_a": 1,"flag_b": 1,"flag_c": 1}
  {"id": 2,"title": "nginx実践入門","price": 2992,"flag_a": 2,"flag_b": 2,"flag_c": 2}
  {"id": 3,"title": "Amazon Web Services実践入門","price": 2786,"flag_a": 3,"flag_b": 3,"flag_c": 3}
  {"id": 4,"title": "APIデザインケーススタディ","price": 3002,"flag_a": 1,"flag_b": 2,"flag_c": 3}
  {"id": 5,"title": "初めてのAnsible","price": 3456,"flag_a": 2,"flag_b": 1,"flag_c": 3}
  {"id": 6,"title": "スターティングGo言語","price": 3218,"flag_a": 3,"flag_b": 2,"flag_c": 1}
  {"id": 7,"title": "RDB技術者のためのNoSQLガイド","price": 3672,"flag_a": 2,"flag_b": 2,"flag_c": 3}
  {"id": 8,"title": "カンバン仕事術","price": 3888,"flag_a": 2,"flag_b": 3,"flag_c": 1}
  {"id": 9,"title": "スクラム現場ガイド -スクラムを始めてみたけどうまくいかない時に読む本-","price": 3758,"flag_a": 3,"flag_b": 1,"flag_c": 3}
  {"id": 10,"title": "Jenkins実践入門","price": 3110,"flag_a": 2,"flag_b": 3,"flag_c": 1}
  {"id": 11,"title": "チーム開発実践入門","price": 2894,"flag_a": 3,"flag_b": 2,"flag_c": 3}
  {"id": 12,"title": "Chef実践入門","price": 2992,"flag_a": 1,"flag_b": 1,"flag_c": 3}
  {"id": 13,"title": "プログラマのためのDocker教科書","price": 3240,"flag_a": 1,"flag_b": 2,"flag_c": 1}
  {"id": 14,"title": "SUPER BOSS(スーパーボス)","price": 1944,"flag_a": 1,"flag_b": 3,"flag_c": 2}
  {"id": 15,"title": "速習ECMAScript6","price": 250,"flag_a": 1,"flag_b": 2,"flag_c": 2}
  {"id": 16,"title": "AngularJS アプリケーションプログラミング","price": 3996,"flag_a": 3,"flag_b": 2,"flag_c": 1}
  {"id": 17,"title": "Ionicで始めるハイブリッドアプリ開発入門","price": 760,"flag_a": 2,"flag_b": 3,"flag_c": 1}
  {"id": 18,"title": "Full Stack Mobile App with Ionic Framework","price": 117,"flag_a": 3,"flag_b": 3,"flag_c": 2}
  {"id": 19,"title": "HTML5 ハイブリッドアプリ開発[実践]入門","price": 3110,"flag_a": 2,"flag_b": 2,"flag_c": 3}
  {"id": 20,"title": "jQuery Mobileスマートフォンアプリ開発","price": 3024,"flag_a": 2,"flag_b": 2,"flag_c": 1}
  {"id": 21,"title": "最高のリーダーは何もしない","price": 1412,"flag_a": 1,"flag_b": 3,"flag_c": 1}

MySQLにも同じ検証データを作成する。

MySQLには以下のようなテーブルを作成しました。

CREATE TABLE IF NOT EXISTS `contents` (
  `id` int(13) NOT NULL,
  `title` varchar(255) NOT NULL,
  `price` int(13) NOT NULL,
  `flag_a` int(13) NOT NULL,
  `flag_b` int(13) NOT NULL,
  `flag_c` int(13) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

データインサート分

INSERT INTO `contents` (`id`, `title`, `price`, `flag_a`, `flag_b`, `flag_c`) VALUES
(1, 'マイクロサービスアーキテクチャ', 3672, 1, 1, 1),
(2, 'nginx実践入門', 2992, 2, 2, 2),
(3, 'Amazon Web Services実践入門', 2786, 3, 3, 3),
(4, 'APIデザインケーススタディ', 3002, 1, 2, 3),
(5, '初めてのAnsible', 3456, 2, 1, 3),
(6, 'スターティングGo言語', 3218, 3, 1, 1),
(7, 'RDB技術者のためのNoSQLガイド', 3672, 2, 2, 3),
(8, 'カンバン仕事術', 3888, 2, 3, 1),
(9, 'スクラム現場ガイド -スクラムを始めてみたけどうまくいかない時に読む本-', 3758, 3, 1, 3),
(10, 'Jenkins実践入門', 3110, 2, 3, 1),
(11, 'チーム開発実践入門', 2894, 3, 2, 3),
(12, 'Chef実践入門', 2992, 1, 1, 3),
(13, 'プログラマのためのDocker教科書', 3240, 1, 2, 1),
(14, 'SUPER BOSS(スーパーボス)', 1944, 1, 3, 2),
(15, '速習ECMAScript6', 250, 1, 2, 2),
(16, 'AngularJS アプリケーションプログラミング', 3996, 3, 2, 1),
(17, 'Ionicで始めるハイブリッドアプリ開発入門', 760, 2, 3, 1),
(18, 'Full Stack Mobile App with Ionic Framework', 117, 3, 3, 2),
(19, 'HTML5 ハイブリッドアプリ開発[実践]入門', 3110, 2, 2, 3),
(20, 'jQuery Mobileスマートフォンアプリ開発', 3024, 2, 2, 1),
(21, '最高のリーダーは何もしない', 1412, 1, 3, 1);

早速叩いてみる

まずは超基本的なクエリでデータが取得できるか検証を行っておきます。

MySQLでIDを単純に取得する場合

$ select * from contents where id=1;
* * * 表示省略 * * * 
1 row in set (0.00 sec)

ElasticSearchの場合

$ curl -XGET 'http://192.168.0.2:9200/test/contents/_search?pretty=true' -d '
{
  "query" : {
    "term" : {
	  "id":1
	}
  }
}'
--------------------------- Responce ---------------------------
{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "test",
      "_type" : "contents",
      "_id" : "1",
      "_score" : 1.0,
      "_source":{"id": 1,"title": "マイクロサービスアーキテクチャ","price": 3672,"flag_a": 1,"flag_b": 1,"flag_c": 1}
    } ]
  }
}

次は、範囲指定での検索を行います
MySQLの場合

$ select * from contents where price between 1000 and 2000;
* * * 表示省略 * * * 
> ID:14とID:21が返却されました。

ElasticSearchの場合

$ curl -XGET 'http://192.168.0.2:9200/test/contents/_search?pretty=true' -d '
{
  "query" : {
    "range" : {
      "price" : {
        "from" : 1000,
        "to" : 2000
      }
    }
  }
}'
--------------------------- Responce ---------------------------
{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "test",
      "_type" : "contents",
      "_id" : "14",
      "_score" : 1.0,
      "_source":{"id": 14,"title": "SUPER BOSS(スーパーボス)","price": 1944,"flag_a": 1,"flag_b": 3,"flag_c": 2}
    }, {
      "_index" : "test",
      "_type" : "contents",
      "_id" : "21",
      "_score" : 1.0,
      "_source":{"id": 21,"title": "最高のリーダーは何もしない","price": 1412,"flag_a": 1,"flag_b": 3,"flag_c": 1}
    } ]
  }
}

数値だけ取得したい場合

MySQLの場合

$ select count(*) as cnt from contents where price between 1000 and 2000;
* * * 表示省略 * * * 
> 2件と表示

ElasticSearchの場合

$ curl -XGET 'http://192.168.0.2:9200/test/contents/_search?pretty=true&search_type=count' -d '
{
  "query" : {
    "range" : {
      "price" : {
        "from" : 1000,
        "to" : 2000
      }
    }
  }
}'
--------------------------- Responce ---------------------------
{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [ ]
  }
}

今回は、検証環境を整えて、簡単なクエリを叩くのが目的でしたので、このへんで!
次回は、もっと複雑で実践的なクエリを叩いていこうと思います。