Rails 中的全文搜尋

類別: IT
標籤: rails

介紹

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

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

專案安裝

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

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

搜尋

首先我們要將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 方法並傳入我們想要搜尋的查詢字串. 這裡我們可以使用到幾個方法來定製我們想要的搜尋結果. [email protected],它將會作用於我們的檢視.

def index
[email protected]= Product.search do
        fulltext params[:search]
    end
[email protected][email protected]
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
[email protected]= 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
[email protected][email protected]
end

在檢視檔案中,將下面的程式碼貼上到你想要看到切片結果的地方.

<div class="row">
    <h3>Search Results</h3>
    <ul>
        <[email protected](: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搜尋引擎或同類玩意來替代它是值得的。

Rails 中的全文搜尋原文請看這裡

推薦文章