ウェブサービスを作っています。

「Elasticsearch: The Definitive Guide」が良い

検索まわりに強くなりたくて、最近は Elasticsearch の勉強をしています。

ただ、ブログの記事や日本語の書籍 (↓) は、情報が古かったり断片的な情報で、いまいち全体像をつかむことができませんでした。

高速スケーラブル検索エンジン ElasticSearch Server

高速スケーラブル検索エンジン ElasticSearch Server

  • 作者: Rafal Kuc・Marek Rogozin’ski,株式会社リクルートテクノロジーズ,大岩達也、大谷純、兼山元太、水戸祐介、守谷純之介
  • 出版社/メーカー: KADOKAWA/アスキー・メディアワークス
  • 発売日: 2014/03/21
  • メディア: 大型本
  • この商品を含むブログ (4件) を見る

そこで、公式サイトにある Elasticsearch: The Definitive Guide を読んでみたところ、わかりやすくてよかったです。

英語なのでちょっとつらいですが、Getting Started まで読むだけでも役立ちそうです。

情報が新しく、Elasticsearch 2.0 に対応しているのも良い点です。


elasticsearch-rails の入門方法

elasticsearch-rails に関しては、サンプルアプリのソースが参考になりました。

WEB+DB PRESS Vol.87 の Elasticsearch 記事も参考になります。

WEB+DB PRESS Vol.87

WEB+DB PRESS Vol.87

  • 作者: 佐藤鉄平,小林明大,石村真吾,坂上卓史,上原誠,鳥居英,佐藤歩,泉水翔吾,うさみけんた,伊藤直也,高橋侑久,佐藤太一,hayajo,橋本翔,西尾泰和,中島聡,はまちや2,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/06/24
  • メディア: 大型本
  • この商品を含むブログ (2件) を見る

elasticsearch:import タスクで eager loading を行う

elasticsearch-rails には、DB のデータを Elasticsearch にインポートするelasticsearch:import という便利な rake タスクがあります。

ただ、has_many などで関連しているデータもインデックスしたい場合に

rake environment elasticsearch:import:all FORCE=y

だけだと、eager loading が行われず、インデックス速度が遅くなってしまいます。

そこで、モデルに

scope :search_import, -> { includes(:categories, :sub_categories) }

のような scope を作ってあげて、

rake environment elasticsearch:import:all SCOPE="search_import" FORCE=y

とすると、eager loading が行われ、インデックス速度を上げることができます。


また、Gemfile に

gem 'ansi'

を追加すると、タスクの実行中にプログレスバーが表示されて便利です。

iTerm2 上の Emacs で、テーマの色を適切に表示する

iTerm2 で Emacs を起動し (emacs -nw)、 テーマを選択すると、適切な色が表示されないことがあります。

調べたところ、iTerm2 の開発版と、パッチを当てた Emacs を使用することで直すことができました。

以下、Homebrew を使用していて、環境変数 TERM が xterm-256color になっている前提です。

使用中の iTerm2、Emacs を削除

brew cask uninstall iterm2
brew uninstall emacs
brew uninstall tmux  # tmux を使っている場合

iTerm2 開発版のインストール

brew tap caskroom/versions
brew cask install iterm2-nightly --appdir=/Applications

パッチを当てた Emacs のインストール

brew install choppsv1/term24/emacs
brew install choppsv1/term24/tmux  # tmux を使っている場合

iTerm2 の再起動

あとは、iTerm2 を起動しなおして、

ITERM_24BIT=1 emacs

とすれば、適切な色が表示されるはずです。

いちいち ITERM_24BIT=1 と打つのは面倒なので、.zshrc などに書いておくと良いと思います。

.zshrc

export ITERM_24BIT=1

参考

できるだけ簡単に ActiveRecord で utf8mb4 を動かす

MySQL で絵文字を扱うのに必要な utf8mb4 の設定方法です。

新規にデータベースを構築する場合向けです。

Rails 4.2.6 で確認しています。

データベースの設定

config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  collation: utf8mb4_bin

encoding を utf8mb4 に、collation を utf8mb4_bin にします。

collation を utf8mb4_bin にすることで、「ハハ」と「パパ」などが同一のものとして扱われるのを防ぎます。

ただし、「A」と「a」などのアルファベット大文字・小文字も別のものとして扱われるようになります。

string の文字数を変更する

インデックス長の関係で、string が VARCHAR(255) ではなく VARCHAR(191) になるようにします。

追記(2017/3/21 15:05):

MySQL 5.7.7 以降では、以下の設定は不要です。( 参考: MySQL 5.7 と絵文字(ちょこっと Rails) - TMD45'β'LOG!!! )

追記ここまで


config/initializers/mysql_utf8mb4_fix.rb

require 'active_record/connection_adapters/abstract_mysql_adapter'

module ActiveRecord
  module ConnectionAdapters
    class AbstractMysqlAdapter
      NATIVE_DATABASE_TYPES[:string] = { name: 'varchar', limit: 191 }
    end
  end
end

参考

active_decorator-rspec gem が便利

Active Decorator の decorator 内で、ヘルパーのメソッドを使っていると、テストをうまく書けないという問題があります。

今までは、

active_decorator のdecoratorをrspecでテストする方法 - アジャイルSEを目指すブログ

を参考にさせていただいていたのですが、これだと、ApplicationController に書いた helper_method がテストで使えないようです。

悩んでいたところ、active_decorator-rspec という便利な gem を見つけました。

Gemfile は、こんな感じ。

gem 'active_decorator'

group :test do
  gem 'active_decorator-rspec', require: false
  gem 'rspec-rails', group: 'development'
end

あとは、spec/rails_helper.rb で

require 'active_decorator/rspec'

と読み込んで、

spec/decorators 内のテストで、

describe UserDecorator, '.hoge' do
  let(:user) { User.new }
  subject { decorate(user).hoge }
end

のように使えます。

最新版の Redis を wercker で使う

wercker/install_redis.sh

if [ ! -d "$WERCKER_CACHE_DIR/redis" ]
then
    mkdir $WERCKER_CACHE_DIR/redis
fi

if [ ! -f "$WERCKER_CACHE_DIR/redis/redis-3.0.2.tar.gz" ]
then
    cd $WERCKER_CACHE_DIR/redis
    wget http://download.redis.io/releases/redis-3.0.2.tar.gz
    tar zxvf redis-3.0.2.tar.gz
    cd redis-3.0.2
    make
    sed -r "s#^daemonize no\$#daemonize yes#;" redis.conf > redis.conf.new
fi

cd $WERCKER_CACHE_DIR/redis/redis-3.0.2
sudo src/redis-server redis.conf.new

wercker.yml

build:
    steps:
        - script:
            name: install redis
            code: sh wercker/install_redis.sh

RSpec で Active Job のテストを書く

追記(2016/11/11 10:33):

この記事の内容は古くなっており、あまりおすすめしません。RSpec 公式の方法をお使い下さい。

追記ここまで


Rails 4.2.1 で確認しています。

Post#ping で、10 分後に PingJob をエンキューするというテストを書いてみます。


spec/rails_helper.rb

RSpec.configure do |config|
  config.include ActiveJob::TestHelper
  config.include ActiveSupport::Testing::TimeHelpers  # 時間関係のテスト (travel_to メソッド) で使用
  ...
end

app/jobs/ping_job.rb

class PingJob < ActiveJob::Base
  queue_as :default

  def perform(msg)
    # do something...
  end
end

app/models/post.rb

class Post < ActiveRecord::Base
  def ping
    PingJob.set(wait: 10.minutes).perform_later 'hello'
  end
end

spec/models/post_spec.rb

require 'rails_helper'

describe Post, '#ping' do
  before { @post = Post.new }

  it '10 分後に PingJob をエンキューする' do
    time = Time.current

    travel_to(time) do
      assertion = {
        job: PingJob,
        args: ['hello'],
        at: (time + 10.minutes).to_i,
      }
      assert_enqueued_with(assertion) { @post.ping }
    end
  end
end

参考