はじめに
こんばんわ,高知工科大学AdventCalendar2017の22日目を担当させていただくTokikaze0604です.
これ書いてる現在12月22日22時前です,すいません.
(途中でブラウザバックが暴発して記事が消えてくたばりかけました,つらい)
今回は,個人的に欲しいなーと思っている,自分のいいね(ふぁぼ)を検索できる何かを作ることにしました.
何か良いアプリとかあったら教えてください.
できたものは一応Githubに置きました.(2017/12/22現在:クローンしてもElasticsearchのgem入れるところで失敗するので,早めに直します. )
2018/01/26追記:去年のうちに修正していたのですが,記事の更新を忘れていました.現在は正常に動作します.
使ったもの
- TwitterAPI
- Ruby
- Ruby on Rails (5)
- Elasticsearch
別にElasticsearchを使うのはmustではなかったのですが,全然最近(?)の技術を触っていない(最近Promelaしか触ってない)ので,何か使ってみたかったので試しに使ってみました.
それに加えて,いい感じに検索してくれるらしいので,そっちも試しに.
やること
- ツイッターからいいね(ふぁぼ)を全件取得する
- Elasticsearchに入れる
- Railsで適当にページ作って表示
大したことはできまsしません.
手順1:ツイッターからいいね(ふぁぼ)を全件取得する
特に面白くもないいいね(ふぁぼ)を取得するRubyのコード.
twitterのgem使ってます.
@client = Twitter::REST::Client.new do |config|
config.consumer_key = ENV['CONSUMER_KEY']
config.consumer_secret = ENV['CONSUMER_SECRET']
config.access_token = ENV['ACCESS_TOKEN']
config.access_token_secret = ENV['ACCESS_TOKEN_SECRET']
end
def get_favs(n = 200, max_id)
@client.favorites(:count => n, :max_id => max_id)
end
max_id
にツイートのID渡すと,そのID以下のツイートがcount
件返ってきます.
最後に取得したツイートのIDをそのまま渡すと1件重複するするので,下のように-1を入れるようにします.
(参考)
res = get_favs(max_id) # max_id以下のidのふぁぼ(ツイート)を取得
res.map do |status|
count = count + 1
max_id = status.id - 1
append_fav(favs, status, count) # ふぁぼをハッシュに格納する
end
もっとあるはずなのに,3154件で終わってしまいました.
最後に取得したいいね(ふぁぼ)が約2ヶ月前なので,2ヶ月が限界なのでしょうか.
ぐぐる力が足りなくて調べきれなかったのですが,もしかして課金APIなら全件取得できる...?
手順2:Elasticsearchに入れる
準備不足で時間が仕方ないので2ヶ月分で我慢してElasticsearchに移ります.
こちらの記事を参考にElasticserachを導入しました.
ただ,elasticsearch-headはElasticsearch5.XXからpluginで入れられなくなったらしいので,別記事を参考に導入しました.
詳しいの説明は省きますが,localhost:9200
にアクセスして以下のような感じなら勝ちです.
次は取得したいいね(ふぁぼ)をElasticsearchにぶち込む過程ですが,
これはもうRailsでやってしまいます.
こちらの記事を参考に,scaffoldで適当に(ちょうど良いという意味だといいな)動くものを作ります.
ツイートのIDは18桁の数値なので,decimal
で取りました.
decimal
使う時はシングルクォーテーションで囲まないとおかしなことになるらしいです.
参考
$ rails new fav
$ cd fav
$ rake db:create
$ bundle exec rails g scaffold favorite 'tweet_id:decimal{18,0}' text:text user_name:string created_at:date
$ bundle exec rake db:migrate
ここまででとりあえずRailsの方ができたので次はElasticsearchのgemを入れて,Elasticsearch用の設定とかを書いていきます.
詳しい部分は参考記事に任せることにして(ほとんどArticleをFavoriteに変えるだけ),
大きく異なる部分のみをご紹介します.
まずは,マッピング情報の設定です.
参考記事では以下のように文字列のマッピングにstring
を設定していますが,
# app/models/concerns/article_searcable.rb
...
# マッピング情報
settings do
mappings dynamic: 'false' do # 動的にマッピングを生成しない
indexes :title, analyzer: 'kuromoji', type: 'string'
indexes :body, analyzer: 'kuromoji', type: 'string'
end
end
...
Elasticsearch6.XXからはtext
と設定するようになったようです.
(参考)
それから,今回は必要ないのですが,何度もツイートを取得・保存することを考えて重複しないようにしました.
(参考)
# app/models/favorite.rb
class Favorite < ApplicationRecord
include FavoriteSearchable
validates :tweet_id, :uniqueness => {:scope => :text} # ここで重複を制限
end
# db/migrate/20171221141005_create_favorites.rb
class CreateFavorites < ActiveRecord::Migration[5.1]
def change
create_table :favorites do |t|
t.decimal :tweet_id, precision: 18, scale: 0
t.text :text
t.string :user_name
t.time :created_at
t.timestamps
end
add_index :favorites, [:tweet_id, :text], unique: true # ここで重複を制限
end
end
手順3:Railsで適当にページ作って表示
最後はViewをいじるのですが,とりあえず検索できれば満足なのでツイッターのリンクを貼るだけにとどめます.
手順にするほどじゃない
# app/views/index.html.erb
<p id="notice"><%= notice %></p>
<h1>Favorites</h1>
<%= form_tag favorites_path, :method => :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag 'Search', :name => nil %>
<% end %>
...
完成
そんな感じで色々と雑完成しました.
rails s
でサーバを立てて,'localhost:3000/favorites'にアクセスすると以下のように表示されます.
何も考えずに本文とユーザ名の両方にマッピングしたので,ユーザ名に検索ワードが入っている人が出てきて見辛い....
(そもそも見た目がひどい)
おわりに
そんなこんなで色々と期待通りの結果は得られませんでしたが,久しぶりにコードを見たり書いたりしたので楽しかったです.
全然Elasticsearchを活かせていないのは確実なので,もうちょっとブラッシュアップしていきたいと思います.
(とりあえずGithubからクローンしても動くようにします...)
稚拙な技術と文章ですが,ここまで読んでくださりありがとうございました.
(次の機会があればもっと余裕を持って投稿します,ごめんなさい)