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

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

ただいまの
回答率

90.53%

  • Ruby on Rails

    7237questions

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

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

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 485

yuta_tokyo

score 25

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

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • moke

    2017/01/26 11:34

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

    キャンセル

  • yuta_tokyo

    2017/01/26 11:38

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

    キャンセル

  • moke

    2017/01/26 11:45

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

    キャンセル

回答 1

+1

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モデルと

acts_as_taggable
before_save :standarize_text,:save_tags
def standarize_text
end
def save_tags
array=check_taggable_word(self.title)
self.tag_list.add(array)
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 //共通部分を返す
end


Commentモデルに

before_save :standarize_text,:save_tags
def standarize_text
重複や入力ブレを治すため文字を大文字とかに直す半角カナも直す、nkfとか使って見てください
end
def save_tags
array=check_taggable_word(self.comment)
self.post.tag_list.add(array)
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 //共通部分を返す
end


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

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

module ActAsTaggleOnPatch
module TagPatch
 def self.included(base)
   base.extend(ClassMethods)
   base.send(:include, InstanceMethods)
   base.class_eval do
     after_commit :set_this_tag_for_post 
     end
   end
  module ClassMethods
  end

  module InstanceMethods
    def set_this_tag_for_post
       regexp=Regexp.new(self.name)
       Post.all.each do |post|

       tag=post.comment.match(regexp)
       if tag
        post.tag_list.add(self.name)
        post.comments.each do |comment|
        c=comment.comment.match(regexp)
         if c
          post.tag_list.add(self.name)
          brake
         end
       end

end

end
end


もちろんinitializer.rbに

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


を入れてください

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/26 12:40

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

    キャンセル

  • 2017/02/06 09:07

    moke様
    ご丁寧な解説ありがとうございます!定期末試験で1週間できませんでしたが、今日から再開します!

    質問です。
    textという表現は、postの内容を指している?
    tagのnameという表現は、tagの内容を指している?
    (それぞれPost、Commentモデル内に書くと指示された部分のものです。)

    また、viewでの表示に関しても御指南いただけましたらと思います!

    キャンセル

  • 2017/02/06 09:29 編集

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

    キャンセル

  • 2017/02/06 09:37

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

    キャンセル

  • 2017/02/06 09:45

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

    キャンセル

  • 2017/02/06 09:52

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

    キャンセル

  • 2017/02/06 10:07

    viewの方はイメージがわかないんですよ
    前も書きましたがどうやるとユーザビリティが上がるか
    わからないので。
    とりあえず
    http://ruby-rails.hatenadiary.com/entry/20150225/1424858414
    とかを見て工夫すればできると思います。

    キャンセル

  • 2017/02/06 10:11

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

    キャンセル

  • 2017/02/06 10:20 編集

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

    キャンセル

  • 2017/02/06 11:02

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

    キャンセル

  • 2017/02/06 11:43

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

    キャンセル

  • 2017/02/06 12:19 編集

    解答3つめの更新を見過ごしていました。
    "他に出てくるtextはただの引数です。"←これはつまり、postモデルの投稿をtitleとカラム名を設定していた場合、titleと書き直すべきですよね?

    また、tagsテーブルというのはどこでどのように作るべきなのでしょうか?
    よろしくお願いします!

    また、新規投稿したら
    undefined method `comment' for #<Post:0x007fa3cdd092b0>
    というエラーがでました。
    array = check_taggable_word(self.comment)
    がエラーに該当する部分とのことです。これはつまりpostした瞬間にはcommentがないからエラーがでるということでよろしいでしょうか?

    キャンセル

  • 2017/02/06 13:25

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

    キャンセル

  • 2017/02/06 14:28

    moke様
    titleにすることで問題が解消しました。

    Could not find table 'taggings'というエラー文が表示され、該当するエラー文は <%= @post.tag_list.join(',') %>とのことです。

    おそらく、tagが登録されていないからということだと思うのですが、いかがでしょうか?
    もし、そうでしたらテーブルにデーターを追加する方法を教えていただきたいです!

    0からすべて教えて頂く形になってしまい誠にすみません。感謝しております!

    キャンセル

  • 2017/02/06 14:38

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

    キャンセル

  • 2017/02/06 14:45 編集

    各commentとpostモデルに追加されるということでよろしいでしょうか?

    追加されません...
    確認方法はrails cでコンソールを立ち上げ、Postの中身を見ました。

    キャンセル

  • 2017/02/06 15:01

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

    キャンセル

  • 2017/02/06 15:25 編集

    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(',') %>とのことです。

    キャンセル

  • 2017/02/06 16:43

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

    キャンセル

  • 2017/02/06 17:00

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

    キャンセル

  • 2017/02/06 17:22

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

    キャンセル

  • 2017/02/06 17:34

    moke様
    お世話になります。現在postに投稿すると以下のようなエラー文がでてきます。
     undefined local variable or method `ary' for #<Post:0x007fb8b5021550>

    また、エラー該当部分はpostsコントローラーの
    return ary & tags #共通部分を返す
    です

    キャンセル

  • 2017/02/06 17:42

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

    キャンセル

  • 2017/02/06 17:45

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

    キャンセル

  • 2017/02/06 17:46

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

    キャンセル

  • 2017/02/06 18:01

    aryの件ありがとうございます!

    tagページの件、試みます!

    //postにのみつける場合はここを変更
    ←これに関してもう少しうかがいたいです。これが含まれるsave_tagsの定義で行なっていることについて教えていただけましたらと思います!

    キャンセル

  • 2017/02/06 18:46

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

    キャンセル

  • 2017/02/06 19:11

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

    キャンセル

  • 2017/02/07 04:00 編集

    なるほど、postとcommentの形態要素分解はmecabに頼っているからということですね。mecabによって形態分解した単語と照らし合わせるtagデーターベースの作成の件ですが、いかがしたらよろしいでしょうか?

    また、重複単語のviewへの吐き出しのところがイマイチ見えてきません...

    キャンセル

  • 2017/02/07 04:13

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

    キャンセル

  • 2017/02/07 04:35

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

    キャンセル

  • 2017/02/07 09:19

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

    キャンセル

  • 2017/02/08 02:16 編集

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

    キャンセル

  • 2017/02/10 07: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につけるかの違いです。

    キャンセル

  • 2017/02/10 08:44

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

    キャンセル

  • 2017/02/10 09:05

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

    キャンセル

  • 2017/02/10 09:20

    もうひとつ質問です。
    post.rbのsave_tagsメソッドの件ですが、
    self.tag_list.add(array)
    を実行するとtagsテーブルにすでに追加されているtagが再び追加されてしまうと思うのですが、

    わざわざtagに追加せず、重複tagを表示させたいのですが、いかがでしょうか?

    キャンセル

  • 2017/02/10 09:34

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

    キャンセル

  • 2017/02/10 09:37

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

    キャンセル

  • 2017/02/16 18:12 編集

    おつかれさまです!自分でそのあといろいろ試してみたのですが、要素分解と重複確認まではうまくいったのですが、重複したものを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

    キャンセル

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

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby on Rails

    7237questions

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