Rails 中的全文搜索

jopen 10年前發布 | 14K 次閱讀 Rails Ruby開發

介紹

在Web應用中,搜索數據記錄是一個常見的需求。最常見的一個需求就是允許用戶從大量的數據記錄中快速訪問他們想要的數據。雖然可以使用簡單的SQL查詢應對這樣的查詢需求,但有時,更有效的是使用搜索引擎。

Solr是Apache Lucene項目中的一個流行的搜索平臺。其主要功能包括強大的全文搜索,點擊顯示,分面搜索,近實時索引,動態聚類,數據庫集成,富文本處理和空間搜索。在本教程中,我們將尋求利用Sunspot執行全文本搜索,Sunspot是一個能夠使Solr集成在ruby應用中的類庫。

項目安裝

我在 Github 創建了一個簡單的app, 我將用在這里而不是開始一個全新的項目。這個 app 顯示了一個產品列表,包括產品名,圖片,價格和描述。我引用了一些 seed 數據,所以如果你不想自己輸入數據的話, 你可以運行 rake db:seed  。這個應用程序使用了Paperclip處理圖片附件,因為我用到圖片大小調整,所以在你的系統需要裝上ImageMagick。隨教程的進行你還需要在你的機器安裝Java運行環境。

下面圖片展示了這個應用程序。頂部的搜索表單現在還沒做什么,但是我們將使得一個用戶通過搜索產品并得到基于不僅僅是產品名,也包括它的商品描述的結果。

Rails 中的全文搜索

搜索

首先我們要將Sunspot和Solr引入到我們的依賴庫中. 在開發中, 我們會使用預打包有Solr發行版的sunspot_solr依賴包, 這樣我們就不需要單獨安裝它了.

gem 'sunspot_rails'
 
group :development do
    gem 'sunspot_solr'
end

運行 bundle install 生成Sunspot配置文件.

 rails generate sunspot_rails:install

這里創建了文件 /config/sunspot.yml 用以讓你的應用知道在哪里找到 Solr 服務器.

建立為你想要索引的對象, 并為其添加searchable塊. 在starter project中, 我們有一個含有name, price, description 和 photo字段的Product模型. 我們要為字段 name 和description 添加全文搜索. 在/models/product.rb中添加:

searchable do
    text :name, :description
end

通過執行下面的語句啟動Solr服務器:

rake sunspot:solr:start

Sunspot 索引你添加的新記錄 , 但是如果數據庫中已經有了許多數據, 執行 rake sunspot:reindex 來索引他們.

然后我們將代碼放入 Products 控制器中,它將會得到用戶的輸入并將其傳入搜索引擎. 在下面的代碼中,我們在一個Product模型上面調用搜索并傳入一個塊. 我們在這個塊中調用 fulltext 方法并傳入我們想要搜索的查詢字符串. 這里我們可以使用到幾個方法來定制我們想要的搜索結果. 然后搜索結果就會被賦值給 @products,它將會作用于我們的視圖.

def index
    @query = Product.search do
        fulltext params[:search]
    end
    @products = @query.results
end

運行應用程序,你就應當能夠用這個程序來搜索可用的產品了. 

Solr 將會使用輸入的關鍵詞或者短句對產品的名稱和描述做一個大小寫敏感的搜索. 你可以通過讓某個域擁有比其它域更多的權重來提升搜索結果的相關性. 這是由 boost 方法來 做到的,它會被傳入一個值來決定不同域的權重. 帶有最大值的域將取得更多的重視. 

在我們的應用程序中,我們可以讓在名稱中搜索到關鍵字符串的產品設置一個較高的分數. 我們可以通過在/models/product.rb中進行如下改變來做到.

searchable do
    text :name, :boost => 2
    text :description
end

使用 rake sunspot:reindex 可以對記錄進行重新索引,而現在在產品名稱中搜索到關鍵字的產品將會比在產品描述中搜索到關鍵字的產品排名要高. 你可以添加更多的記錄來測試這一點.

切片瀏覽

切片瀏覽是一種通過將相關屬性進行不同組合的方式來瀏覽查詢數據. 例如, 在我們的應用程序中,我們可以依據價格級別來分類搜索產品,并給出每一個級別的總數.

首先將價格添加到 /models/product.rb 中的searchable方法中

searchable do
    text :name, :boost => 2
    text :description
    double :price
end

然后在控制器中調用 facet . 產品就會根據按 $100.00 為間隔的價格級別來切片 . 這里我們假定所有的產品價錢都低于 $500.

def index
    @query = Product.search do
        fulltext params[:search]
 
        facet :price, :range => 0..500, :range_interval => 100
        with(:price, Range.new(*params[:price_range].split("..").map(&:to_i))) if params[:price_range].present?
 
    end
    @products = @query.results
end

在視圖文件中,將下面的代碼粘貼到你想要看到切片結果的地方.

<div class="row">
    <h3>Search Results</h3>
    <ul>
        <% for row in @query.facet(:price).rows %>
            <li>
                <% if params[:price_range].blank? %>
                    <%= link_to row.value, :price_range => row.value, :search => params[:search] %> (<%= row.count %>)
                <% else %>
                    <%= row.value %> (<%= link_to "X", :price_range => nil %>)
                <% end %>
            </li>
        <% end %>
    </ul>
</div>

現在,當你搜索一個條目時,將會有一個切片列表展示出在每個價格級別會有多少條結果 . 在我們的示例應用程序中,如果你搜索關鍵詞 'camera', 你將會看到下面這份列表.

100.0..200.0 (2)
200.0..300.0 (1)
300.0..400.0 (1)

每一項都是一個鏈接,并且當在上面點擊的時候,你將會獲得一個滿足你的搜索條件,并且其價格也會落在你所點擊的相應區間的產品列表. 

鏈接向index動作傳入了原有的查詢關鍵詞,以及點擊所選擇的價格區間 . 由于其傳入的價格區間是一個字符串,我們要使用 Range.new(*params[:price_range].split("..").map(&:to_i)) 來將其轉換回區間. 你可以使用條件語句來輸出更多對用戶友好的連接,比如像$100 - $199 (2) 而不是 100.0..200.0 (2) ,但這里我們不會深入討論這個.

高級的配置

你可以使用更多的配置來定制Solr的運作 . 在其默認的配置中, Sunspot 通過使用一個智能的叫做StandardTokenizer的標記生成器基于空格和其它分隔符將搜索字符串分成多個關鍵詞標記 . 然后這些關鍵詞標記將會被轉換成小寫并被提取出搜索的關鍵詞.

這有時可能已經夠可以的了,但你也許還需要對搜索引擎進行配置,以容許人工錯誤或不太嚴謹的查詢. 比如,你可能想要要向引擎提供一些同義詞,那樣當用戶并沒有輸入匹配你記錄中的精確文本時,他們仍然能得到一個類似的結果. 一個例子就是你可能在記錄中有標記為 'ipod' 的數據項. 你可能會提供想 'iPod', 'i-pod' 和 'i pod' 的同義詞,來增加用戶找到數據的可能性.

另外一個你可以添加的實用功能是詞干搜索, 其將允許Solr實用相同的詞干匹配不同的關鍵詞. 例如,如果用戶輸入了 'run', 他們會得到帶有 'run' 和 'running'的結果. 或者如果他們搜索'walk', 結果將會包含含有 'walk', 'walking', 'walked', 等等關鍵詞的數據.

Solr 的設置可以在 solr/conf/schema.xml 中找到,這個文件可以修改用來改變服務器的配置. 這超出了本教程的范圍,而作為對此的更深入介紹,請查看 全文搜索的高級配置 以及 Solr wiki.

結論

現在來總結一下,通過執行下面的命令停止Solr服務:

rake sunspot:solr:stop

我們已經搞了一把借助Sunspot gem來整合Solr搜索引擎到Rails應用,除了那些我們已經固定的設置外,還有很多搜索的設置是可以個性化設置的,大家可以通過閱讀Readme File找到更多選項來玩玩。

Solr給你提供了一種通過傳統SQL語句沒法達成的搜索能力。對于那些簡單的應用,數據庫記錄也很少,通過SQL來搜索是沒有性能瓶頸的,但如果你想要靈活升級,用Solr搜索引擎或同類玩意來替代它是值得的。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!