LoginSignup
9
3

More than 3 years have passed since last update.

はじめてのElasticsearch

Last updated at Posted at 2019-12-21

どうも、今年もそろそろ終わりということで、やり残していたElasticsearchデビューしようと思います!
本業務でも導入していきたいという意気込みも込めて!

目標

やるからには目標を持ってやろうと思います!

  • テキスト検索
  • 緯度経度検索
  • 時間検索

をできるようになることを目標とします!(ローカル環境のテストデータにて)

まずは環境を整える

Elasticsearchをダウンロードします(Version: 7.5.0)
https://www.elastic.co/jp/downloads/elasticsearch

ファイルを展開して、Elasticsearch起動!

$ bin/elasticsearch
publish_address {127.0.0.1:9200}, bound_addresses {[::1]:9200}, {127.0.0.1:9200}

どうやら9200ポートで立ち上がりました!

Kibanaもダウンロードします(Version: 7.5.0)
https://www.elastic.co/jp/downloads/kibana

Kibanaも起動!
*KibanaはElasticSearchにブラウザから接続するために必要

$ bin/kibana
http server running at http://localhost:5601

Kibanaも無事5601ポートで立ち上がりました! :100:

Kibanaからデータ登録&データ取得してみる

先ほど立ち上げたKibanaを http://localhost:5601 をブラウザで確認
そしてDev toolsコンソールを開きます

コンソールから先ほど立ち上げたElasticsearch(http://localhost:9200) にリクエストできます

まずは、データ登録

今回は2件の仮想の店舗データを登録します

POST /restaurants/_doc
{
  "name": "太平洋に浮かぶレストラン"
}

POST /restaurants/_doc
{
  "name": "日本海に浮かぶレストラン"
}

そして、登録したデータを取得

検索条件を絞らずに検索してみます

リクエスト
GET /restaurants/_search

無事2件のデータが取得できます!

レスポンス
"hits" : [
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "5idkDG8Br1D6GrZbRdpB",
    "_score" : 1.0,
    "_source" : {
      "name" : "太平洋に浮かぶレストラン"
    }
  },
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "5ydkDG8Br1D6GrZbSdoz",
    "_score" : 1.0,
    "_source" : {
      "name" : "日本海に浮かぶレストラン"
    }
  }
]

これで準備はOKなので、これより目標として掲げたもの遂行していきます!

目標1 テキスト検索

テキスト検索は下記のようにqueryにmatchを使うことで絞り込めます
店舗名に「海」を含む店舗を取得するにはnameに「海」を指定してリクエストしてみると

リクエスト
GET /restaurants/_search
{
  "query": {
    "match": {
      "name": "海"
    }
  }
}

先ほど登録した「日本海に浮かぶレストラン」のみが取得できてます!

レスポンス
"hits" : [
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "5ydkDG8Br1D6GrZbSdoz",
    "_score" : 0.6931472,
    "_source" : {
      "name" : "日本海に浮かぶレストラン"
    }
  }
]

また、SQLもパラメータに渡せるようなので、下記のようにリクエストしてみると

リクエスト
POST /_sql?format=json
{
    "query": "SELECT * FROM restaurants where name like '%海%'"
}

先ほどと返却値は異なりますが、日本海に浮かぶレストランが取得できています

レスポンス
{
  "columns" : [
    {
      "name" : "name",
      "type" : "text"
    }
  ],
  "rows" : [
    [
      "日本海に浮かぶレストラン"
    ]
  ]
}

他にも論理式や否定、どの単語に一致したかわかるハイライト検索もできるようですが、目標2へ先を急ぎます

目標2 緯度経度検索

まず先ほどと同じ要領で緯度経度情報をもつlocationを追加してデータを登録します

リクエスト
POST /restaurants/_doc
{
  "name": "太平洋に浮かぶレストラン",
  "location": {
    "lat": "29.651658",
    "lon": "156.085510"
  }
}

POST /restaurants/_doc
{
  "name": "日本海に浮かぶレストラン",
  "location": {
    "lat": "38.956739",
    "lon": "134.230957"
  }
}

そして、緯度経度検索をできるようにするには、登録した緯度経度のデータがgeo pointのtypeでマッピングされている必要があります

現在のデータのマッピング情報を/restaurants/_mappingで確認してみると

リクエスト
GET /restaurants/_mapping

緯度経度情報として登録していたlocationがtextとして登録されてしまっています、、
これでは緯度経度検索できません、、

レスポンス
"location" : {
  "properties" : {
    "lat" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "lon" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    }
  }
}

気を取り直して、登録しなおします!

まずは、登録データを一旦削除

リクエスト
DELETE restaurants

そして、マッピングを定義(緯度経度を入れるlocationをgeo_typeとマッピング)

リクエスト
PUT /restaurants
PUT /restaurants/_mapping
{
  "properties": {
    "location": {
      "type": "geo_point"
    }
  }
}

そして、再登録

リクエスト
POST /restaurants/_doc
{
  "name": "太平洋に浮かぶレストラン",
  "location": {
    "lat": "29.651658",
    "lon": "156.085510"
  }
}

POST /restaurants/_doc
{
  "name": "日本海に浮かぶレストラン",
  "location": {
    "lat": "38.956739",
    "lon": "134.230957",
  }
}

マッピング情報を再度確認してみると

リクエスト
GET /restaurants/_mapping

typeがgeo_pointになっていることが確認できます! :relaxed:

レスポンス
"location" : {
  "type" : "geo_point"
}

準備が整ったので、これで緯度経度検索できます!
現在地を日本海にして検索してみると(近い順にソートさせてみると)

リクエスト
GET /restaurants/_search
{
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat":  38.956739,
          "lon": 134.230957
        },
        "order": "asc"
      }
    }
  ]
}

意図通り日本海のレストランが先に取得できています!
目標2完了!

レスポンス
"hits" : [
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "7SdvDG8Br1D6GrZbYdoH",
    "_score" : null,
    "_source" : {
      "name" : "日本海に浮かぶレストラン",
      "location" : {
        "lat" : "38.956739",
        "lon" : "134.230957"
      }
    },
    "sort" : [
      0.0
    ]
  },
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "7CdvDG8Br1D6GrZbWNqp",
    "_score" : null,
    "_source" : {
      "name" : "太平洋に浮かぶレストラン",
      "location" : {
        "lat" : "29.651658",
        "lon" : "156.085510"
      }
    },
    "sort" : [
      2250187.1065158164
    ]
  }
]

目標3 時間検索

時間検索も緯度経度検索と同じ要領で進めていけます!

まずは営業時間として、開始時間のbusiness_start_time、終了時間のbusiness_end_timeのマッピング情報を定義します!

リクエスト
PUT /restaurants/_mapping
{
  "properties": {
    "business_start_time": {
      "type" : "date",
      "format": "yyyy/MM/dd HH:mm"
    },
    "business_end_time": {
      "type" : "date",
      "format": "yyyy/MM/dd HH:mm"
    }
  }
}

次に店舗登録

リクエスト
POST /restaurants/_doc
{
  "name": "太平洋に浮かぶレストラン",
  "business_start_time": "2019/12/22 17:00",
  "business_end_time": "2019/12/22 20:00"
}

マッピング情報を確認

リクエスト
GET /restaurants/_mapping

想定どおり、business_start_timeとbusiness_end_timeのtypeがdateになっています

レスポンス
"business_end_time" : {
  "type" : "date",
  "format" : "yyyy/MM/dd HH:mm"
},
"business_start_time" : {
  "type" : "date",
  "format" : "yyyy/MM/dd HH:mm"
}

18:00に営業している店舗があるかどうか検索してみると
(boolとmustを使うことでand検索ができます)

リクエスト
GET /restaurants/_search
{
  "query": {
    "bool": {
      "must": [
        { "range" : { "business_start_time" : { "lte" : "2019/12/22 18:00" } } },
        { "range" : { "business_end_time" : { "gte" : "2019/12/22 18:00" } } }
      ]
    }
  }
}

意図通り12/22 17:00 ~ 20:00 営業している太平洋に浮かぶレストランが取得できています!

レスポンス
"hits" : [
  {
    "_index" : "restaurants",
    "_type" : "_doc",
    "_id" : "-ieSDG8Br1D6GrZbKNrv",
    "_score" : 2.0,
    "_source" : {
      "name" : "太平洋に浮かぶレストラン",
      "business_start_time" : "2019/12/22 17:00",
      "business_end_time" : "2019/12/22 20:00"
    }
  }
]

まとめ

基本的な操作はこれで抑えれます!
より複雑な検索をしたいときは公式ドキュメントを参考にすればできるはず

明日は@tsun3さんの「こわくないJavaScript」です。お楽しみに!

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3