2

Railsアプリ内の静的ページにインデックスを付けて検索機能を追加する方法に関する優れたgemまたはドキュメントを知っている人はいますか? これまでのところ、検索の結果、SunspotCobwebにたどり着きましたが、どちらも私が達成しようとしているものよりも少し複雑なようです。

私のビューディレクトリがどのように見えるかの例を次に示します:

views
|
|__Folder_1
   |
   |__ View-1
   |__ View-2
   |
   Folder_2
   |
   |__ View-3
   |__ View-4

これを設定する方法を検討するときに違いが生じる場合、各フォルダーは定義されたアクションとしてのビューを持つコントローラーです。最終的な目標は、検索された用語を含むページへのリンクのリストを返すことです。

編集:

各検索クエリは、すべての静的ページの HTML コンテンツをクロールし、検索されたストップ ワード以外の用語に一致するページのリンクのリストを返すことを目的としています。また、静的なページ内で検索された用語の頻度と単語の配置に基づいて、検索に関連性を追加する予定です。

例:

検索クエリ: 「スクランブルエッグのレシピ」 - 「レシピ」、「スクランブルエッグ」、「卵」という単語を含むページへのリンクを返し、最も関連性の高いリンクが返されたリストの一番上に配置されます。

Search Results:
Page 1 (Most relevant because includes all 3 terms)
Page 2 (Includes 2 terms)
Page 3 (Includes 1 terms)

できれば、検索機能は、検索語を各ビューのテキストに一致させようとするだけで、ユーザーが検索語として「div」を入力した場合、HTML コンテンツ内に div 要素が存在するため、すべてのページが返されるわけではありません。

答え:

Ruby を数週間勉強した後、これが私が思いついたものです - 基本的に、/app/views/ ディレクトリ内の各サブディレクトリをフィルタリングし、サブディレクトリのコンテンツ内の各ファイルを読み取り、テキストを処理して HTML を削除していますタグと一般的なストップ ワードを検索し、検索インデックス ハッシュ内に格納します。

search_controller.rb

#include sanitize helper to enable use of strip_tags method in controller
include ActionView::Helpers::SanitizeHelper

class SearchController < ApplicationController

  prepend_before_filter :search

  def search
    if params[:q]
      stopwords = ["a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by", "can't", "cannot", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "don't", "down", "during", "each", "few", "for", "from", "further", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him", "himself", "his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "isn't", "it", "it's", "its", "itself", "let's", "me", "more", "most", "mustn't", "my", "myself", "no", "nor", "not", "of", "off", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", "same", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "wasn't", "we", "we'd", "we'll", "we're", "we've", "were", "weren't", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's", "whom", "why", "why's", "with", "won't", "would", "wouldn't", "you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself"]
      #cleanse all stop words from search query
      @search_terms = strip_tags(params[:q]).downcase.split.delete_if{|x| stopwords.include?(x)}

      #declare empty index hash
      @search_index = {}

      #filter through each view and add view text to search entry
      Rails.root.join('app', "views").entries.each do |view_dir| 
        unless %w(. .. search shared layouts).include?(view_dir.to_s) 
          Rails.root.join('app', "views", view_dir.to_s).entries.each do |view| 
            unless %w(. ..).include?(view.to_s)
              #add relative path for view and processed contents to search index hash as key, value pair
              @search_index["/" + view_dir.to_s + "/" + view.to_s.gsub('.html.erb', '')] = strip_tags(IO.read(Rails.root.join('app', "views", view_dir.to_s, view.to_s))).downcase.squish.split.delete_if{|x| stopwords.include?(x)}.join(" ")
            end
          end
        end
      end

    end
  end

end

改善点や提案があれば、ぜひお聞かせください。

4

1 に答える 1

1

検索用語とそれらが一致するビューの定義済みリストがある場合は、ハードコードされた用語インデックスを使用して、静的ページ検索機能の限定バージョンを実装できます。

# app/controllers/searches_controller.rb
class SearchesController < ApplicationController
  def index
    query = params[:query]

    # Convert query string to lowercase tokens, e.g. 
    # /search?query=cAT+aNd+doG => ['cat', 'and', 'dog']
    terms = query.downcase.split

    # Match each search term against the index, collecting all matching pages.
    @pages = terms.collect do |term|
      get_search_index[term]
    end

    # Remove nil objects resulting from terms not matching anything.
    @pages.compact!

    # Flatten all nested arrays into one array of pages for easy looping.
    @pages.flatten!
  end

  private
    def get_search_index
      @@index ||= {
        "homepage" => [
          {:path => root_path, :name => "Home"}
        ],
        "home" => [
          {:path => root_path, :name => "Home"}
        ],
        "user" => [
          {:path => new_user_path, :name => "Create New User"}, 
          {:path => users_path, :name => "User Index"}
        ]
      }
    end
end

ビューについては次のとおりです。

# app/views/searches/index.html.erb
Search results:
<ol>
<% @pages.each do |page| %>
    <li><%= link_to page[:name], page[:path] %></li>
<% end %>
</ol>

これ/searches?query=some+User+pageで、新しいユーザー フォームとユーザー インデックス ページの両方が検索結果に表示されます (「ユーザー」という用語が一致したため)。

この静的なアプローチを拡張して、より凝ったものにすることもできます。たとえば、用語をハードコーディングする代わりに、実際に静的ページからテキスト本文の例を取得し、それを用語に分割することができます。例えば:

# Get a corpus, lowercase it, replace punctuation with whitespace, and tokenize.
@@homepage_terms = "Block of homepage text.".downcase.gsub(/[^a-z0-9]/, ' ').split
@@about_page_terms = "Block of about page text.".downcase.gsub(/[^a-z0-9]/, ' ').split

def get_search_index
  # Memoize the index so we only build it once.
  @@index ||= build_search_index
end

def build_search_index
  index = {}
  @@homepage_terms.each do |term|
    index[term] ||= []
    index[term] << {path: root_path, name: "Home"}
  end
  @@about_page_terms.each do |term|
    index[term] ||= []
    index[term] << {path: root_path, name: "About page"}
  end
  index
end

関数build_search_indexは、必要に応じて複雑で機能豊富にすることができます。本質的に、あなたがしていることは車輪の再発明です。Solr やその他の検索バックエンドは、この種の作業を行うために構築されました。ランキングの実行、ディスクからのビュー ファイルの読み取り、および HTML サニタイズは、読者の演習として残します :)

より動的なもの、つまりページの変更に合わせて自動的に調整するものが必要な場合は、views フォルダーをスキャンしてハッシュが生成されることを除いて、同様に見えます。ただし、動的なアプローチははるかに複雑です。1 つは、検索結果の人間が読めるページ タイトルをどこで取得するかということです。そのメタデータは Rails のどこにも含まれていません。また、どのページが GET ページであるかはどのようにしてわかりますか? 安全なページや検索結果に表示したくないページがある場合はどうすればよいでしょうか? さらに、ERBを解釈する必要があります。静的ビューをサーバー側でレンダリングすることは不可能ではありませんが、これらのページがユーザーごとに異なる場合はどうなるでしょうか? そして、国際化についてはどうですか?

上記のような手動でキュレートされたソリューションは、私にとって最良の選択肢のようです. あなたのサイトがほとんどの場合、静的ページはそれほど変更されないため、メンテナンスは大きな問題にはなりません。

于 2013-08-03T01:44:56.790 に答える