質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

1回答

1561閲覧

DB内のキーワードとテキストの照合について

yuta_tokyo

総合スコア35

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2017/01/25 18:23

はじめまして、ruby on rails初めて1ヶ月と1日がたちました。

現在制作している掲示板もなんとか形になってきました。
今回は投稿されたテキスト内にDBに保存されているキーワードがあった場合、キーワードとしてリンク化(いわゆるタグ化)する実装の流れについてご教授いただきたいです。

いま、想定される問題は以下です。
・参照するDB内のキーワードの量が200を越すことが想定されます。リンクを生成し投稿完了画面への遷移時に遅延が発生しないか。

また、現在想定している実装の流れは以下です。
・参照用のDBの作成
・投稿テキストにDBのキーワードを総当て(ここの実装が難しいです)
・重複キーワードをviewにリンクタグとして表示する

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moke

2017/01/26 00:35

えっtagだったんですか
moke

2017/01/26 00:43

すると投稿→解析→こんなtagがついたよでも編集できないよ(結果画面表示)ってことですか?
moke

2017/01/26 00:43

そのtagは誰がいつ使うのですか?
yuta_tokyo

2017/01/26 01:44

タグです!すみません説明不足で...
yuta_tokyo

2017/01/26 01:45

タグのアーカイブで関連記事を見れる仕組みを作りたいのです!
moke

2017/01/26 01:58

掲示板ならpostだけにつければいいのでは?commentにいちいちつけているとごちゃごちゃしますよ。
yuta_tokyo

2017/01/26 02:01

postとcommentのテキストからタグを生成し、../posts/(数字)のpostページに関連するタグとして表示したいのです。
yuta_tokyo

2017/01/26 02:02

commentによってあたらしく話題が変わったりもするとおもうので!
moke

2017/01/26 02:04

commentにあるkey_wordをpostにつけるとか
yuta_tokyo

2017/01/26 02:05

commentにあるkey_wordというと具体的にどういうことでしょうか?
moke

2017/01/26 02:09

やはり目的がわからないと答えようがないですね、サジェストなのかリコメンドなのか記事の重複防止なのか、はたまた検索補助なのか
moke

2017/01/26 02:12

postのcommentにkey_word[ほげ]が出てきたらcommentにtagをつけずpostにほげtagがつくといった感じです
yuta_tokyo

2017/01/26 02:16

postとcommentにkey_word[ほげ]が出てきたら、例えば一番最後のcommentのしたにkey_word[ほげ]のリンクを表示させたいです。目的としてはpostをkey_wordアーカイブに結びつけることによって、内部リンクを自動で増やしていくことです。
moke

2017/01/26 02:17

えっ SEO対策?
yuta_tokyo

2017/01/26 02:20

seo対策です!(ユーザービリティも上がるとも考えていますが、今回は割愛させていただきます)
moke

2017/01/26 02:24

じゃあ、そう書いてください、なんか違和感があったのですが。少なくとも、私は今までに同ドメイン内でのリンクの数がSEO対策になるという話は聞いたことがありません
yuta_tokyo

2017/01/26 02:26

ご不便おかけしたことすみません!このような仕様でしたらどのような実装の流れがよろしいでしょうか?
moke

2017/01/26 02:30

えっと、だから私の知る限りではこれがSEO対策になるとは思えないのですが
yuta_tokyo

2017/01/26 02:31

ユーザービリティの面でも是非実装したいのですが、それでもでしょうか?
moke

2017/01/26 02:34

では教えてください。サジェストなのかリコメンドなのか記事の重複防止なのか、はたまた検索補助なのか
yuta_tokyo

2017/01/26 02:38

アーカイブへのリンクによるユーザービリティ向上です(リコメンドに近いきもしますが、一覧を見れる形になるのでリコメンドとはいいきれません)
moke

2017/01/26 02:45

ユーザーとしてはかえって邪魔そうな機能だなーと思いますがとりあえず回答書きますね
guest

回答1

0

gem 'acts-as-taggable-on'
gem 'natto'
をgemfileに追加
bundle install
rake acts_as_taggable_on_engine:install:migrations
rake db::migrateを実行
Postモデルに
acts_as_taggable
を追加
Postモデルと

ruby

1acts_as_taggable 2before_save :standarize_text,:save_tags 3def standarize_text 4end 5def save_tags 6array=check_taggable_word(self.title) 7self.tag_list.add(array) 8end 9def check_taggable_word(text) 10ary=Array.new 11 nm = Natto::MeCab.new 12 nm.parse(text) do |n| 13 ary<<n.surface 14 end //mekabuで要素に分解 15tags=ActsAsTaggableOn::Tag.pluck(:name)//タグを取得 16return ary & tags //共通部分を返す 17end

Commentモデルに

ruby

1before_save :standarize_text,:save_tags 2def standarize_text 3重複や入力ブレを治すため文字を大文字とかに直す半角カナも直す、nkfとか使って見てください 4end 5def save_tags 6array=check_taggable_word(self.comment) 7self.post.tag_list.add(array) 8end 9def check_taggable_word(text) 10ary=Array.new 11 nm = Natto::MeCab.new 12 nm.parse(text) do |n| 13 ary<<n.surface 14 end //mekabuで要素に分解 15tags=ActsAsTaggableOn::Tag.pluck(:name)//タグを取得 16return ary & tags //共通部分を返す 17end

こんな感じですかね
mekabuライブラリで文章を単語に分解して作ったarrayと
tagに登録されている全ての単語のtagsの共通部分を取っています

あと新たなtagが追加されるたびに全てのコメントにそのタグがないかチェックして
追加する機能が必要です。
パッチを追加してact_as_taggle_onのtag classを拡張して見てください

ruby

1module ActAsTaggleOnPatch 2module TagPatch 3 def self.included(base) 4 base.extend(ClassMethods) 5 base.send(:include, InstanceMethods) 6 base.class_eval do 7 after_commit :set_this_tag_for_post 8 end 9 end 10 module ClassMethods 11 end 12 13 module InstanceMethods 14 def set_this_tag_for_post 15 regexp=Regexp.new(self.name) 16 Post.all.each do |post| 17 18 tag=post.comment.match(regexp) 19 if tag 20 post.tag_list.add(self.name) 21 post.comments.each do |comment| 22 c=comment.comment.match(regexp) 23 if c 24 post.tag_list.add(self.name) 25 brake 26 end 27 end 28 29end 30 31end 32end

もちろんinitializer.rbに

ruby

1ActsAsTaggableOn::Tag.send(:include,ActsAsTaggableOnPatch::TagPatch)

を入れてください

投稿2017/01/26 03:35

編集2017/02/06 09:44
moke

総合スコア2241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moke

2017/01/26 03:40

あと新たなtagが追加されるたびに全てのコメントにそのタグがないかチェックして 追加する機能が必要です。それはlibにパッチを追加してact_as_taggle_onのtag classを拡張して見てください
yuta_tokyo

2017/02/06 00:07

moke様 ご丁寧な解説ありがとうございます!定期末試験で1週間できませんでしたが、今日から再開します! 質問です。 textという表現は、postの内容を指している? tagのnameという表現は、tagの内容を指している? (それぞれPost、Commentモデル内に書くと指示された部分のものです。) また、viewでの表示に関しても御指南いただけましたらと思います!
moke

2017/02/06 00:42 編集

定期試験お疲れ様です textは文字列って意味です。 standarize_textは受け取った文字列を標準化(入力のブレをなくす)する関数です。 他に出てくるtextはただの引数です。 tagのnameはacts-as-taggable-onを使えば追加されるtagの名前です。
yuta_tokyo

2017/02/06 00:37

早速のご返信ありがとうございます! 上記のtag(acts-as-taggable-onで再生されたもの)と、postモデルのtagカラム(これから作ります)は重複しても大丈夫なのでしょうか?
moke

2017/02/06 00:45

postモデルにtagカラムを作る必要はございません。 (仮にそのアイデアだと複数のtagがついた時どう処理するのですか?) acts_as_taggable とmodelに追記すればよろしくやってくれます。
yuta_tokyo

2017/02/06 00:52

なるほどです!ありがとうございます!また、viewでの表示の件はいかがでしょうか?
yuta_tokyo

2017/02/06 01:11

掲示板に投稿されるpostとcommentをmecabを用いて形態素分解をし、登録されているtag(データーベース?)と比較し、重複していたら、リンク付きキーワードとしてpost投稿ページに関連キーワードとして表示させるというイメージです。構造化とseoの関係はこちらを参考にしています。http://blog.livedoor.jp/kensuu/archives/54268130.html
moke

2017/02/06 01:21 編集

それは覚えてますよ。本当にそれだけでいいなら @post.tag_list.join(',') で十分だと思いますが ユーザビリティ?って感じがするので
yuta_tokyo

2017/02/06 02:02

ユーザビリティはABテストで今後しっかりみていきたいと思います! tagの追加というのはコンソール開いて、post.tag_list.add("きーわーど1")と追加していくしかないのでしょうか? 現在、上のpost.tag_list.add("きーわーど1")を試すとエラーがでてきます。 NameError: undefined local variable or method `post' for main:Object
moke

2017/02/06 02:43

post はmodel Postのインスタンスです。 登録だけしたいなら tagsテーブルにエクセルで作ったデータを貼り付ければいいのでは?
yuta_tokyo

2017/02/06 03:27 編集

解答3つめの更新を見過ごしていました。 "他に出てくるtextはただの引数です。"←これはつまり、postモデルの投稿をtitleとカラム名を設定していた場合、titleと書き直すべきですよね? また、tagsテーブルというのはどこでどのように作るべきなのでしょうか? よろしくお願いします! また、新規投稿したら undefined method `comment' for #<Post:0x007fa3cdd092b0> というエラーがでました。 array = check_taggable_word(self.comment) がエラーに該当する部分とのことです。これはつまりpostした瞬間にはcommentがないからエラーがでるということでよろしいでしょうか?
moke

2017/02/06 04:25

私はエスパーでないので、わからない情報は想像で書いています。 そのまま動いたら奇跡です、適宜読み替えてください。 この場合これも想像ですがcommentをtitleにすればいいのでは? あと引数(ひきすう)の意味がわからないなら調べましょう。 tagsテーブルは bundle installして rake db::migrateすれば できているはずです。 あと今度から初心者マークをつけるべきです。
yuta_tokyo

2017/02/06 05:28

moke様 titleにすることで問題が解消しました。 Could not find table 'taggings'というエラー文が表示され、該当するエラー文は <%= @post.tag_list.join(',') %>とのことです。 おそらく、tagが登録されていないからということだと思うのですが、いかがでしょうか? もし、そうでしたらテーブルにデーターを追加する方法を教えていただきたいです! 0からすべて教えて頂く形になってしまい誠にすみません。感謝しております!
moke

2017/02/06 05:38

gem act_as_taggable_on を追加 bundle install して rake db::migrate すれば tags,taggins の両テーブルが追加されると思うのですが
yuta_tokyo

2017/02/06 05:57 編集

各commentとpostモデルに追加されるということでよろしいでしょうか? 追加されません... 確認方法はrails cでコンソールを立ち上げ、Postの中身を見ました。
moke

2017/02/06 06:01

DBにtags,tagginsというテーブルが追加されます。 それを確認してください エラーメッセージはタグが登録されていませんという意味ではなく tagginsというテーブルが見つかりませんと言っています。
yuta_tokyo

2017/02/06 07:12 編集

Gamefileにgem 'acts-as-taggable-on'を追加し、 bundle install bundle exec rake db:migrate を実行後 DBのテーブルを見たところ、やはりtagginsとtagsというテーブルは追加されていませんでした。上記の流れでエラー文は表示されていません。 現在のエラーは以下のままです Could not find table 'taggings'というエラー文が表示され、該当するエラー文は <%= @post.tag_list.join(',') %>とのことです。
moke

2017/02/06 07:43

rake acts_as_taggable_on_engine:install:migrations すみませんこれを忘れてました。
yuta_tokyo

2017/02/06 08:00

tagsとtaggingsのテーブルを作ることができました! この2つのテーブルに違いはありますか? このテーブルへデータを挿入するのはコマンドから一斉にやるのがよろしいのでしょうか?
yuta_tokyo

2017/02/06 08:22

この現状だと同じタグを持つpost同士を紐づける(一覧用の)tagページは生成できない状況ですよね? rake routesで確認したところtags関連の情報を取得できなかったので。
yuta_tokyo

2017/02/06 08:34

moke様 お世話になります。現在postに投稿すると以下のようなエラー文がでてきます。  undefined local variable or method `ary' for #<Post:0x007fb8b5021550> また、エラー該当部分はpostsコントローラーの return ary & tags #共通部分を返す です
moke

2017/02/06 08:42

arr からaryに変わってますねすみません
moke

2017/02/06 08:45

tagsは登録されているtagのリストでtaggingsはtagとモデルpostやccommentを紐づけるのに使います。
moke

2017/02/06 08:46

この現状だと同じタグを持つpost同士を紐づける(一覧用の)tagページは生成できない状況ですよね? もちろんですご自分で作成してください。
yuta_tokyo

2017/02/06 09:01

aryの件ありがとうございます! tagページの件、試みます! //postにのみつける場合はここを変更 ←これに関してもう少しうかがいたいです。これが含まれるsave_tagsの定義で行なっていることについて教えていただけましたらと思います!
moke

2017/02/06 09:46

大したことはないです。 commentが登録された時commentにtagをつけるか postにつけるかの違いです。
moke

2017/02/06 10:11

tagページでユーザビリティが決定しますので 頑張ってください。 あとmecabを使って適当に作っていますので おそらくキーワードが貯蓄貯金魚とかだとhitしないと思います。 下手すると経済政策みたいな複合語も怪しいかもしれません。 そもそも話の本筋と全然関係いの無いキーワードを拾ってしまうかもしれません。 本筋をコンピュータに理解させるのは結構難しく、本格的にやろうとすると遺伝子アルゴリズムや人工知能の領域になってしまいます。だから普通tagは手で入力させるのです。もしくは消せるようにするとか。
yuta_tokyo

2017/02/06 19:07 編集

なるほど、postとcommentの形態要素分解はmecabに頼っているからということですね。mecabによって形態分解した単語と照らし合わせるtagデーターベースの作成の件ですが、いかがしたらよろしいでしょうか? また、重複単語のviewへの吐き出しのところがイマイチ見えてきません...
yuta_tokyo

2017/02/06 19:13

また、//postのみにつけるの部分ですが、 現在以下のエラー文 undefined method `tag_list' for #<Comment:0x007fb8b0a88728> が表示され、エラー該当部分は self.tag_list.add(array) #postにのみつける場合はここを変更 だと表示されています。いかがなものでしょうか...
yuta_tokyo

2017/02/06 19:35

今,tagページを生成するべく実装の流れを考えているのですが、 tagsとtaggingsはテーブルであって、modelは新しくつくるべきなのでしょうか? つまり、"rails generate scaffold Tags tag:text"でgenerateすべきでしょうか?
moke

2017/02/07 00:19

回答の方を修正していますよ 各モデルは私の書いたコードを見るとヒントがありますが ActsAsTaggableOn::Tag ActsAsTaggableOn::Tagging で拾えますよ
yuta_tokyo

2017/02/08 02:06 編集

moke様 #self.tag_list.add(array) #postにのみつける場合はここを変更 以上の文が理解できません。これは」、tagにarray(post,commentが要素分解されて、tagとの重複が確認されたもの)を追加という文かと思うのですが、 重複したものは追加するのではなく、表示させたいのです。
yuta_tokyo

2017/02/09 22:59

moke様 お疲れ様です、2017/02/06 18:46の解答の件ですが、 //postにのみついける場合はここを変更の部分をcomment.rbから削除した場合、commentにtagをつけることはできないと思うのですが、いかがでしょうか?現在のプログラムだと、self.tag_list.add(array) 部分をコメントアウトするとコメントが可能ですが、moke様のコードのままコメントをするとundefined method `tag_list'とエラーが表示されます。 #2017/02/06 18:46のmoke様の解答 commentが登録された時commentにtagをつけるか postにつけるかの違いです。
yuta_tokyo

2017/02/09 23:44

2017/02/10 07:59の質問はpost.rbにacts_as_taggableを追加することでfixしました!
yuta_tokyo

2017/02/10 00:05

tagテーブルに形態要素した言葉と照らし合わせるtagを追加する方法はなんでしょうか? つまり、ActsAsTaggableOn::Tag.pluck(:name)がとってくるデーターを追加する方法はなんでしょうか? よろしくお願いします!
yuta_tokyo

2017/02/10 00:20

もうひとつ質問です。 post.rbのsave_tagsメソッドの件ですが、 self.tag_list.add(array) を実行するとtagsテーブルにすでに追加されているtagが再び追加されてしまうと思うのですが、 わざわざtagに追加せず、重複tagを表示させたいのですが、いかがでしょうか?
moke

2017/02/10 00:34

self.tag_list.add(array)はtaggingsに追加されます。重複はしないようです。 tagsにはあるか確認してなければ追加という形です。 ActsAsTaggableOn::Tagにcreate_allとかできるんじゃないですか? 無理ならふつうにActsAsTaggableOn::Tag.create(:name=>'hoge')とかをeachで回わせばいいのでは? 最終手段としてsqlserverにexcelの値を貼り付けるとか まあ、なんにせよ、この最終手段を試してから質問してください
moke

2017/02/10 00:37

>>わざわざtagに追加せず、重複tagを表示させたいのですが、いかがでしょうか? もはや意図の分からない質問には答えかねます。 ベアプログラミングというのがあります試してはいかがでしょう?
yuta_tokyo

2017/02/19 23:24 編集

おつかれさまです!自分でそのあといろいろ試してみたのですが、要素分解と重複確認まではうまくいったのですが、重複したものをtaggingテーブルに保存することと、viewにリンクを表示させることができません。 また何故かpost.save_tagsをコンソール上(以下コード)で二度行うと一度目はエラーがでますが、二度目は成功します。なぜ一度で成功できないのでしょうか? 上記二点アドバイス頂きたく思います! ////////コンソール irb(main):001:0> post = Post.find_by(id:61) Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 61], ["LIMIT", 1]] => #<Post id: 61, title: "タグと太陽、テスト", name: "あああ", created_at: "2017-02-14 01:21:03", updated_at: "2017-02-17 01:21:03", category_id: 1, ip: "::1"> irb(main):002:0> post => #<Post id: 61, title: “タグと太陽、テスト”, name: "あああ", created_at: "2017-02-14 01:21:03", updated_at: "2017-02-17 01:21:03", category_id: 1, ip: "::1"> irb(main):003:0> post.save_tags (0.2ms) SELECT "tags"."name" FROM "tags" ActsAsTaggableOn::Tagging Load (0.2ms) SELECT "taggings".* FROM "taggings" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ? [["taggable_id", 61], ["taggable_type", "Post"]] ActsAsTaggableOn::Tag Load (0.2ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = ? AND "taggings"."taggable_type" = ? AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) [["taggable_id", 61], ["taggable_type", "Post"]] [] "ポストタグテスト中 save_tags" => "ポストタグテスト中 save_tags" irb(main):004:0> post.save_tags (0.1ms) SELECT "tags"."name" FROM "tags" [“タグ”, “太陽”] "ポストタグテスト中 save_tags" => "ポストタグテスト中 save_tags" /////post.rb(self.check_taggable_wordにしています) def save_tags array = self.check_taggable_word(self.title) p self.tag_list self.tag_list.add(array) #postにのみつける場合はここを変更 #self.save p "ポストタグテスト中 save_tags" end def check_taggable_word(text) ary = Array.new nm = Natto::MeCab.new nm.parse(text) do |n| ary<<n.surface end #mekabuで要素に分解 tags = ActsAsTaggableOn::Tag.pluck(:name) #タグを取得 return ary & tags #共通部分を返す p "ポストタグテスト中 check_taggable_word" end
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問