LoginSignup
38
34

More than 5 years have passed since last update.

趣味サービスにElasticsearchを導入しようとしたまとめ

Posted at

はじめに

趣味でわいわい作っているサービスがあります。このサービスに検索機能をつけたいという話になりました。

最新の人気Webサービス・アプリが見つかる Service Safari

このサービスは新サービスがキュレーターによって毎日投稿されて、それがアプリとかWebとかメールで見れるというサービスです。現状でも名前で検索したり、タグで検索したりはできるのですが、今回は複数タグでの検索や紹介文の全文検索機能をつけたいという要件です。MySQLだとつらそうなのでElasticsearchを使ってみることにしました。

  • サービス名の部分一致で検索できる
  • サービス紹介文の全文検索ができる
  • 複数のタグでの検索ができる
  • サービスURLのドメインで検索ができる

上記の項目で複合検索ができることをゴールとします。

まったくのElasticsearch初心者がやっていることなど間違っているところもあるかもしれません。あらかじめご了承くださいm(__)m

VPSに環境構築

Elasticsearchインストール

インストール自体はめちゃくちゃ簡単でyumでできます。Javaが必要です。

/etc/yum.repos.d/elasticsearch.repo
[elasticsearch-2.x]
name=Elasticsearch repository for 2.x packages
baseurl=http://packages.elastic.co/elasticsearch/2.x/centos
gpgcheck=1
gpgkey=http://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1
# yum install java
# yum install elasticsearch

プラグインのインストール

Elasticsearchにはプラグインの仕組みがあり、簡単にいろん以下の3つのプラグインをインストールします。

# cd /usr/share/elasticsearch/
# bin/plugin install analysis-kuromoji
# bin/plugin install lmenezes/elasticsearch-kopf/v2.1.1
# bin/plugin install https://github.com/jlinn/elasticsearch-analysis-url/releases/download/v5.0.0.0/elasticsearch-analysis-url-5.0.0.0.zip

バージョンなどを合わせないとインストール失敗するらしいのでgithubのページなどを参考にしつついれます。

Elasticsearchの基礎

インストールが終わったら、Elasticsearchの基礎について学んでおきます。

用語や概念

Elasticsearch システム概要 – Hello! Elasticsearch. – Medium

この辺の記事を読めばなんとなくわかった気になれます。要点としては、

  • Index: RDBのデータベース
  • Type: RDBのテーブル
  • Document: RDBのレコード

--

  • Cluster: Elasticsearchのプロセスの集合体(Nodeの集まり)
  • Node: Elasticsearchプロセスの1つ1つ
  • Shard: Indexを物理領域的に分割したもの

--

  • Filter: 与えられた文字列を前後処理するもの。例えばスペースを取り除くなど。
  • Tokenizer: 与えられた文字列を分割するもの。分割した文字列でインデックスが作成される。例えばURLを受け取って、ドメインに分割するなど。
  • Analyzer: FilterとTokenizerを組み合わせた処理機構。

という感じでしょうか。正直Node数やShard数をどのくらいに設定するのが適切なのかはまったくわかってません。今回試した例では、2 Nodeでやってますが、お遊びサービスなので本番では1 Nodeで運用しようかと思っています。

Index設計について

Elasticsearchのインデックス定義を設計する手順 - $shibayu36->blog;

こちらの記事がとても参考になりました。要は想定される入力を、

  • どのように整形するか
  • どのように分割するか

みたいなことを考えてそれを設定に落とし込む作業をします。

設定

Elasticsearchの設定

ザクッと書くとこんな感じになりました。

  • network.bind_host: ElasticsearchがbindするIPアドレスで複数設定できる。
  • network.publish_host: これは同クラスタの他のノードと通信するようのIPアドレス(たぶん)
  • discovery.zen.ping.unicast.hosts: 同クラスタの他のノードのIP(もっとスマートな方法はないものか)
  • index以下はアナライザーの設定になります

今回は2Nodeを想定しているので、2つのサーバに同じ設定で discovery.zen.ping.unicast.hosts だけ変更したものを設定します。つまりどころとしては、Firewallで9200と9300ポートを開けるのを忘れないこと。あと今回はグローバルIP降ってますが、通常運用の場合は開けないと思います。

/etc/elasticsearch/elasticsearch.yml
cluster.name: service-safari
node.name: ss1
network.bind_host: ["グローバルIP", "プライベートIP"]
network.publish_host: "プライベートIP"
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["クラスタリングするサーバのプライベートIP"]

index :
    analysis :
        analyzer :
            ja :
                type : custom
                tokenizer : ja_tokenizer
                char_filter : [
                    html_strip,
                    kuromoji_iteration_mark
                ]
                filter : [
                    lowercase,
                    cjk_width,
                    katakana_stemmer,
                    kuromoji_part_of_speech
                ]

            ja_ngram :
                type : custom
                tokenizer : ngram_ja_tokenizer
                char_filter : [html_strip]
                filter : [
                    cjk_width,
                    lowercase
                ]

            url_host:
                tokenizer: url_host

        tokenizer :
            ja_tokenizer :
               type : kuromoji_tokenizer
               mode : search
               # user_dictionary : /etc/elasticsearch/userdict_ja.txt

            ngram_ja_tokenizer :
                type : nGram
                min_gram : 2
                max_gram : 3
                token_chars : [letter, digit]

            url_host:
                type: url
                part: host

        filter :
            katakana_stemmer :
                type : kuromoji_stemmer

Index設定

サービスサファリという名前のIndexを作る場合
PUT /servicesafari

{
  "settings": {
    "index": {
      "number_of_shards": "3",
      "number_of_replicas": "1"
    }
  },
  "mappings": {
    "posts": {
      "_source": {
        "enabled": false
      },
      "_all": {
        "enabled": false
      },
      "properties": {
        "name": {
          "analyzer": "ja_ngram",
          "type": "string"
        },
        "tags": {
          "type": "string"
        },
        "description": {
          "analyzer": "ja_ngram",
          "type": "string"
        }, 
        "url": {
          "type": "string",
          "analyzer": "url_host"
        },
        "related_links": {
          "type": "string",
          "analyzer": "url_host"
        },
        "created_at": {
          "format": "YYYY-MM-dd HH:mm:ss",
          "type": "date"
        }
      }
    }
  }
}

データの登録

POST /servicesafari/posts/1

{
  "created_at" : "2016-11-01 12:00:00",
  "name": "サービスサファリ - ServiceSafari",
  "description": "最新のサービスが知れるメディアです。",
  "tags": ["メディア", "ポータル"],
  "url": "http://www.service.safari.com",
  "related_links": [
    "https://www.producthunt.com/",
    "https://techcrunch.com/",
    "http://eiei19.hatenablog.com/"
  ]
}

データの検索

POST /servicesafari/posts/_search

{
  "query":{"match":{"name":"Service"}}
}

この辺の記事が参考になります。

elasticsearchとSQL対比しながら理解 - Qiita
Elasticsearchのbool queryを利用してAND OR NOTを書いてみる - Qiita

bulkでインポートとか

requests.json
{ "create" : { "_index" : "ss", "_type" : "posts", "_id" : "1" } }
{ "created_at" : "2016-11-01 12:00:00",  "name": "サービスサファリ - ServiceSafari",  "description": "最新のサービスが知れるメディアです。",  "url": "http://www.service.safari.com",  "related_links": [    "https://www.producthunt.com/",    "https://techcrunch.com/",    "http://eiei19.hatenablog.com/"  ]}
{ "create" : { "_index" : "ss", "_type" : "posts", "_id" : "2" } }
{ "created_at" : "2016-11-01 12:00:00",  "name": "Yahoo Japan",  "description": "昔からある老舗のポータル",  "url": "http://yahoo.co.jp",  "related_links": [    "http://news.yahooo.com",    "http://nifty.com",    "http://google.co.jp"  ]}
curl -s -XPOST http://IPアドレス:9200/_bulk --data-binary "@requests.json"; echo

公式ドキュメントを読むべし。

Bulk API | Elasticsearch Reference [5.0] | Elastic

まとめ

以上、Elasticsearchの設定をまとめてみました。あとはアプリケーション側から操作する仕組みを整えていけば使えそうな感じがします。

最新の人気Webサービス・アプリが見つかる Service Safari

Service Safariは趣味のサービスですが、一緒に開発やサービスグロースしてくれるメンバーを募集しています。未経験歓迎なので興味があれば @eiei19 までご連絡ください。Twitterも同じです。

38
34
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
38
34