文件 • 社群論壇 • Stack Overflow • 回報錯誤 • 常見問題 • 支持
這個 gem 可讓您輕鬆地將 Algolia Search API 整合到您最喜歡的 ORM 中。它基於 algoliasearch-client-ruby gem。支援 Rails 6.x 和 7.x。
您可能對提供基於autocomplete.js
的自動完成和基於InstantSearch.js
的即時搜尋結果頁面的範例 Ruby on Rails 應用程式感興趣:algoliasearch-rails-example。
您可以在 Algolia 網站上找到完整的參考資料。
設定
用法
選項
objectID
指數
測試
故障排除
gem install algoliasearch-rails
將 gem 加入您的Gemfile
:
gem "algoliasearch-rails"
並運行:
bundle install
建立一個新檔案config/initializers/algoliasearch.rb
來設定您的APPLICATION_ID
和API_KEY
。
AlgoliaSearch . configuration = { application_id : 'YourApplicationID' , api_key : 'YourAPIKey' }
該 gem 與 AltiveRecord、Mongoid 和 Sequel 相容。
您可以透過在初始化時設定以下選項來配置各種逾時閾值:
AlgoliaSearch . configuration = {
application_id : 'YourApplicationID' ,
api_key : 'YourAPIKey' ,
}
這個 gem 廣泛使用 Rails 的回呼來觸發索引任務。如果您使用繞過after_validation
、 before_save
或after_commit
回呼的方法,它不會索引您的變更。例如: update_attribute
不執行驗證檢查,且要在更新時執行驗證,請使用update_attributes
。
AlgoliaSearch
模組注入的所有方法都以algolia_
為前綴,並為關聯的短名稱(如果尚未定義)添加別名。
Contact . algolia_reindex! # <=> Contact.reindex!
Contact . algolia_search ( "jon doe" ) # <=> Contact.search("jon doe")
以下程式碼將建立一個Contact
索引並在您的Contact
模型中添加搜尋功能:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
attributes :first_name , :last_name , :email
end
end
您可以指定要傳送的屬性(這裡我們限制為:first_name, :last_name, :email
)或不指定(在這種情況下,將發送所有屬性)。
class Product < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
# all attributes will be sent
end
end
您也可以使用add_attribute
方法來傳送所有模型屬性 + 額外的屬性:
class Product < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
# all attributes + extra_attr will be sent
add_attribute :extra_attr
end
def extra_attr
"extra_val"
end
end
我們提供了多種配置索引的方法,讓您可以調整整體索引相關性。最重要的是可搜尋屬性和反映唱片流行度的屬性。
class Product < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
# list of attribute used to build an Algolia record
attributes :title , :subtitle , :description , :likes_count , :seller_name
# the `searchableAttributes` (formerly known as attributesToIndex) setting defines the attributes
# you want to search in: here `title`, `subtitle` & `description`.
# You need to list them by order of importance. `description` is tagged as
# `unordered` to avoid taking the position of a match into account in that attribute.
searchableAttributes [ 'title' , 'subtitle' , 'unordered(description)' ]
# the `customRanking` setting defines the ranking criteria use to compare two matching
# records in case their text-relevance is equal. It should reflect your record popularity.
customRanking [ 'desc(likes_count)' ]
end
end
要為模型建立索引,只需在類別上呼叫reindex
即可:
Product . reindex
若要索引所有模型,您可以執行下列操作:
Rails . application . eager_load! # Ensure all models are loaded (required in development).
algolia_models = ActiveRecord :: Base . descendants . select { | model | model . respond_to? ( :reindex ) }
algolia_models . each ( & :reindex )
傳統的搜尋實作往往在後端具有搜尋邏輯和功能。當搜尋體驗包括使用者輸入搜尋查詢、執行該搜索,然後重定向到搜尋結果頁面時,這是有意義的。
不再需要在後端實現搜尋。事實上,在大多數情況下,由於增加了網路和處理延遲,這對效能有害。我們強烈建議使用我們的 JavaScript API 用戶端直接從最終用戶的瀏覽器、行動裝置或用戶端發出所有搜尋請求。它將減少整體搜尋延遲,同時減輕伺服器的負擔。
JS API 用戶端是 gem 的一部分,只需在 JavaScript 清單中的某個位置需要algolia/v3/algoliasearch.min
,例如,如果您使用的是 Rails 3.1+,則在application.js
中:
//= require algolia/v3/algoliasearch.min
然後在你的 JavaScript 程式碼中你可以這樣做:
var client = algoliasearch ( ApplicationID , Search - Only - API - Key ) ;
var index = client . initIndex ( 'YourIndexName' ) ;
index . search ( 'something' , { hitsPerPage : 10 , page : 0 } )
. then ( function searchDone ( content ) {
console . log ( content )
} )
. catch ( function searchFailure ( err ) {
console . error ( err ) ;
} ) ;
我們最近(2015 年 3 月)發布了 JavaScript 用戶端的新版本 (V3),如果您使用的是我們之前的版本 (V2),請閱讀遷移指南
注意:我們建議使用 JavaScript API 用戶端直接從最終使用者瀏覽器執行查詢,而無需通過您的伺服器。
搜尋會傳回符合 ORM 的對象,並從資料庫重新載入它們。我們建議使用 JavaScript API 用戶端來執行查詢,以減少整體延遲並減輕伺服器負擔。
hits = Contact . search ( "jon doe" )
p hits
p hits . raw_answer # to get the original JSON raw answer
每個 ORM 物件都會新增一個highlight_result
屬性:
hits [ 0 ] . highlight_result [ 'first_name' ] [ 'value' ]
如果您想從 API 檢索原始 JSON 答案,而不從資料庫重新載入對象,您可以使用:
json_answer = Contact . raw_search ( "jon doe" )
p json_answer
p json_answer [ 'hits' ]
p json_answer [ 'facets' ]
搜尋參數可以透過模型中靜態的索引設定來指定,也可以在搜尋時動態指定搜尋參數作為search
方法的第二個參數:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
attribute :first_name , :last_name , :email
# default search parameters stored in the index settings
minWordSizefor1Typo 4
minWordSizefor2Typos 8
hitsPerPage 42
end
end
# dynamical search parameters
p Contact . raw_search ( 'jon doe' , { hitsPerPage : 5 , page : 2 } )
即使我們強烈建議使用 JavaScript 從前端執行所有搜尋(因此分頁)操作,我們也支援 will_paginate 和 kaminari 作為分頁後端。
要使用:will_paginate
,請指定:pagination_backend
如下:
AlgoliaSearch . configuration = { application_id : 'YourApplicationID' , api_key : 'YourAPIKey' , pagination_backend : :will_paginate }
然後,一旦使用search
方法,傳回的結果將是一個分頁集:
# in your controller
@results = MyModel . search ( 'foo' , hitsPerPage : 10 )
# in your views
# if using will_paginate
<%= will_paginate @results %>
# if using kaminari
<%= paginate @results %>
使用tags
方法將標籤新增到您的記錄中:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
tags [ 'trusted' ]
end
end
或使用動態值:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
tags do
[ first_name . blank? || last_name . blank? ? 'partial' : 'full' , has_valid_email? ? 'valid_email' : 'invalid_email' ]
end
end
end
查詢時,指定{ tagFilters: 'tagvalue' }
或{ tagFilters: ['tagvalue1', 'tagvalue2'] }
作為搜尋參數,以將結果集限制為特定標籤。
可以呼叫搜尋答案的facets
方法來檢索 Facets。
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
# [...]
# specify the list of attributes available for faceting
attributesForFaceting [ :company , :zip_code ]
end
end
hits = Contact . search ( 'jon doe' , { facets : '*' } )
p hits # ORM-compliant array of objects
p hits . facets # extra method added to retrieve facets
p hits . facets [ 'company' ] # facet values+count of facet 'company'
p hits . facets [ 'zip_code' ] # facet values+count of facet 'zip_code'
raw_json = Contact . raw_search ( 'jon doe' , { facets : '*' } )
p raw_json [ 'facets' ]
您也可以搜尋構面值。
Product . search_for_facet_values ( 'category' , 'Headphones' ) # Array of {value, highlighted, count}
此方法也可以採用查詢可以採用的任何參數。這會將搜尋調整為僅符合查詢的命中。
# Only sends back the categories containing red Apple products (and only counts those)
Product . search_for_facet_values ( 'category' , 'phone' , {
query : 'red' ,
filters : 'brand:Apple'
} ) # Array of phone categories linked to red Apple products
有關分組的不同資訊的更多資訊可以在此處找到。
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
# [...]
# specify the attribute to be used for distinguishing the records
# in this case the records will be grouped by company
attributeForDistinct "company"
end
end
使用geoloc
方法本地化您的記錄:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
geoloc :lat_attr , :lng_attr
end
end
查詢時,指定{ aroundLatLng: "37.33, -121.89", aroundRadius: 50000 }
作為搜尋參數,以將結果集限制為聖荷西周圍 50KM。
每次儲存一筆記錄時,都會對其進行非同步索引。另一方面,每次銷毀記錄時,它都會從索引中非同步刪除。這意味著具有 ADD/DELETE 操作的網路呼叫會同步發送到 Algolia API,但隨後引擎將非同步處理該操作(因此,如果您在之後進行搜索,結果可能還沒有反映出來)。
您可以停用自動索引和自動刪除設定以下選項:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch auto_index : false , auto_remove : false do
attribute :first_name , :last_name , :email
end
end
您可以使用without_auto_index
範圍暫時停用自動索引。這通常出於性能原因而使用。
Contact . delete_all
Contact . without_auto_index do
1 . upto ( 10000 ) { Contact . create! attributes } # inside this block, auto indexing task will not run.
end
Contact . reindex! # will use batch operations
您可以設定自動索引和自動刪除程序以使用佇列在背景執行這些操作。預設使用 ActiveJob (Rails >=4.2) 佇列,但您可以定義自己的排隊機制:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch enqueue : true do # ActiveJob will be triggered using a `algoliasearch` queue
attribute :first_name , :last_name , :email
end
end
如果您在背景執行更新和刪除,則可以在作業實際執行之前將記錄刪除提交到您的資料庫。因此,如果您要載入記錄以將其從資料庫中刪除,那麼您的 ActiveRecord#find 將失敗並顯示 RecordNotFound。
在這種情況下,您可以繞過從 ActiveRecord 載入記錄,而直接與索引通訊:
class MySidekiqWorker
def perform ( id , remove )
if remove
# the record has likely already been removed from your database so we cannot
# use ActiveRecord#find to load it
index = AlgoliaSearch . client . init_index ( "index_name" )
index . delete_object ( id )
else
# the record should be present
c = Contact . find ( id )
c . index!
end
end
end
如果您使用的是 Sidekiq:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch enqueue : :trigger_sidekiq_worker do
attribute :first_name , :last_name , :email
end
def self . trigger_sidekiq_worker ( record , remove )
MySidekiqWorker . perform_async ( record . id , remove )
end
end
class MySidekiqWorker
def perform ( id , remove )
if remove
# the record has likely already been removed from your database so we cannot
# use ActiveRecord#find to load it
index = AlgoliaSearch . client . init_index ( "index_name" )
index . delete_object ( id )
else
# the record should be present
c = Contact . find ( id )
c . index!
end
end
end
如果您使用的是delayed_job:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch enqueue : :trigger_delayed_job do
attribute :first_name , :last_name , :email
end
def self . trigger_delayed_job ( record , remove )
if remove
record . delay . remove_from_index!
else
record . delay . index!
end
end
end
您可以透過設定以下選項來強制索引和刪除同步(在這種情況下,gem 將呼叫wait_task
方法以確保該方法在返回後已考慮該操作):(不建議這樣做,除非用於測試目的)
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch synchronous : true do
attribute :first_name , :last_name , :email
end
end
預設情況下,索引名稱將是類別名稱,例如“Contact”。您可以使用index_name
選項自訂索引名稱:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch index_name : "MyCustomName" do
attribute :first_name , :last_name , :email
end
end
您可以使用下列選項在索引名稱後面新增目前 Rails 環境的字尾:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch per_environment : true do # index name will be "Contact_#{Rails.env}"
attribute :first_name , :last_name , :email
end
end
您可以使用區塊來指定複雜的屬性值
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
attribute :email
attribute :full_name do
" #{ first_name } #{ last_name } "
end
add_attribute :full_name2
end
def full_name2
" #{ first_name } #{ last_name } "
end
end
注意:一旦您使用此類程式碼定義額外的屬性,gem 就不再能夠偵測屬性是否已變更(程式碼使用 Rails 的#{attribute}_changed?
方法來偵測)。因此,即使其屬性沒有更改,您的記錄也會被推送到 API。您可以透過建立_changed?
來解決此行為。方法:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch do
attribute :email
attribute :full_name do
" #{ first_name } #{ last_name } "
end
end
def full_name_changed?
first_name_changed? || last_name_changed?
end
end
您可以輕鬆嵌入定義額外屬性的巢狀對象,傳回任何符合 JSON 的物件(陣列或雜湊或兩者的組合)。
class Profile < ActiveRecord :: Base
include AlgoliaSearch
belongs_to :user
has_many :specializations
algoliasearch do
attribute :user do
# restrict the nested "user" object to its `name` + `email`
{ name : user . name , email : user . email }
end
attribute :public_specializations do
# build an array of public specialization (include only `title` and `another_attr`)
specializations . select { | s | s . public? } . map do | s |
{ title : s . title , another_attr : s . another_attr }
end
end
end
end
對於 ActiveRecord,我們將使用touch
和after_touch
來實現這一點。
# app/models/app.rb
class App < ApplicationRecord
include AlgoliaSearch
belongs_to :author , class_name : :User
after_touch :index!
algoliasearch do
attribute :title
attribute :author do
author . as_json
end
end
end
# app/models/user.rb
class User < ApplicationRecord
# If your association uses belongs_to
# - use `touch: true`
# - do not define an `after_save` hook
has_many :apps , foreign_key : :author_id
after_save { apps . each ( & :touch ) }
end
使用 Sequel,您可以使用touch
外掛來傳播變更:
# app/models/app.rb
class App < Sequel :: Model
include AlgoliaSearch
many_to_one :author , class : :User
plugin :timestamps
plugin :touch
algoliasearch do
attribute :title
attribute :author do
author . to_hash
end
end
end
# app/models/user.rb
class User < Sequel :: Model
one_to_many :apps , key : :author_id
plugin :timestamps
# Can't use the associations since it won't trigger the after_save
plugin :touch
# Define the associations that need to be touched here
# Less performant, but allows for the after_save hook to trigger
def touch_associations
apps . map ( & :touch )
end
def touch
super
touch_associations
end
end
objectID
預設情況下, objectID
是基於您的記錄的id
。您可以透過指定:id
選項來變更此行為(請確保使用 uniq 欄位)。
class UniqUser < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch id : :uniq_name do
end
end
您可以新增約束來控制是否必須使用:if
或:unless
選項對記錄建立索引。
它允許您對每個文件進行條件索引。
class Post < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch if : :published? , unless : :deleted? do
end
def published?
# [...]
end
def deleted?
# [...]
end
end
注意:一旦您使用這些約束,就會執行addObjects
和deleteObjects
調用,以保持索引與資料庫同步(無狀態 gem 不知道該物件是否不再與您的約束匹配或從未匹配) ,因此我們強制發送ADD/ DELETE 操作)。您可以透過建立_changed?
來解決此行為。方法:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch if : :published do
end
def published
# true or false
end
def published_changed?
# return true only if you know that the 'published' state changed
end
end
您可以使用下列任一方法對記錄的子集建立索引:
# will generate batch API calls (recommended)
MyModel . where ( 'updated_at > ?' , 10 . minutes . ago ) . reindex!
或者
MyModel . index_objects MyModel . limit ( 5 )
您可以使用sanitize
選項清理所有屬性。它將從您的屬性中刪除所有 HTML 標籤。
class User < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch per_environment : true , sanitize : true do
attributes :name , :email , :company
end
end
如果您使用Rails 4.2+,您還需要依賴rails-html-sanitizer
:
gem 'rails-html-sanitizer'
您可以使用force_utf8_encoding
選項強制對所有屬性進行UTF-8編碼:
class User < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch force_utf8_encoding : true do
attributes :name , :email , :company
end
end
注意:此選項與 Ruby 1.8 不相容
您可以使用raise_on_failure
選項來停用嘗試存取 Algolia 的 API 時可能引發的例外:
class Contact < ActiveRecord :: Base
include AlgoliaSearch
# only raise exceptions in development env
algoliasearch raise_on_failure : Rails . env . development? do
attribute :first_name , :last_name , :email
end
end
這是一個真實的設定範例(來自 HN Search):
class Item < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch per_environment : true do
# the list of attributes sent to Algolia's API
attribute :created_at , :title , :url , :author , :points , :story_text , :comment_text , :author , :num_comments , :story_id , :story_title
# integer version of the created_at datetime field, to use numerical filtering
attribute :created_at_i do
created_at . to_i
end
# `title` is more important than `{story,comment}_text`, `{story,comment}_text` more than `url`, `url` more than `author`
# btw, do not take into account position in most fields to avoid first word match boost
searchableAttributes [ 'unordered(title)' , 'unordered(story_text)' , 'unordered(comment_text)' , 'unordered(url)' , 'author' ]
# tags used for filtering
tags do
[ item_type , "author_ #{ author } " , "story_ #{ story_id } " ]
end
# use associated number of HN points to sort results (last sort criteria)
customRanking [ 'desc(points)' , 'desc(num_comments)' ]
# google+, $1.5M raises, C#: we love you
separatorsToIndex '+#$'
end
def story_text
item_type_cd != Item . comment ? text : nil
end
def story_title
comment? && story ? story . title : nil
end
def story_url
comment? && story ? story . url : nil
end
def comment_text
comment? ? text : nil
end
def comment?
item_type_cd == Item . comment
end
# [...]
end
您可以使用index!
實例方法。
c = Contact . create! ( params [ :contact ] )
c . index!
並使用remove_from_index!
實例方法。
c . remove_from_index!
c . destroy
gem 提供了 2 種方法來重新索引所有物件:
要重新索引所有記錄(考慮到已刪除的物件), reindex
類別方法會將所有物件索引到名為<INDEX_NAME>.tmp
臨時索引,並在所有內容都被索引(原子地)後將臨時索引移動到最後一個索引。這是重新索引所有內容的最安全方法。
Contact . reindex
注意:如果您使用特定於索引的 API 金鑰,請確保您允許<INDEX_NAME>
和<INDEX_NAME>.tmp
。
警告:在確定/過濾模型範圍時不應使用此類原子重新索引操作,因為此操作會取代整個索引,僅保留過濾後的物件。即:不要執行MyModel.where(...).reindex
,而是執行MyModel.where(...).reindex!
(有尾隨!
)!
若要重新索引所有物件(沒有臨時索引,因此不會刪除已刪除的物件),請使用reindex!
類別方法:
Contact . reindex!
要清除索引,請使用clear_index!
類別方法:
Contact . clear_index!
您可以透過呼叫index
類別方法來存取底層index
物件:
index = Contact . index
# index.get_settings, index.partial_update_object, ...
您可以使用add_replica
方法定義副本索引。如果您希望副本區塊繼承主設置,請在副本區塊上使用inherit: true
。
class Book < ActiveRecord :: Base
attr_protected
include AlgoliaSearch
algoliasearch per_environment : true do
searchableAttributes [ :name , :author , :editor ]
# define a replica index to search by `author` only
add_replica 'Book_by_author' , per_environment : true do
searchableAttributes [ :author ]
end
# define a replica index with custom ordering but same settings than the main block
add_replica 'Book_custom_order' , inherit : true , per_environment : true do
customRanking [ 'asc(rank)' ]
end
end
end
要使用副本進行搜索,請使用以下程式碼:
Book . raw_search 'foo bar' , replica : 'Book_by_editor'
# or
Book . search 'foo bar' , replica : 'Book_by_editor'
在多個模型之間共用索引是有意義的。為了實現這一點,您需要確保與底層模型的objectID
沒有任何衝突。
class Student < ActiveRecord :: Base
attr_protected
include AlgoliaSearch
algoliasearch index_name : 'people' , id : :algolia_id do
# [...]
end
private
def algolia_id
"student_ #{ id } " # ensure the teacher & student IDs are not conflicting
end
end
class Teacher < ActiveRecord :: Base
attr_protected
include AlgoliaSearch
algoliasearch index_name : 'people' , id : :algolia_id do
# [...]
end
private
def algolia_id
"teacher_ #{ id } " # ensure the teacher & student IDs are not conflicting
end
end
注意:如果您針對多個模型的單一索引,則絕對不能使用MyModel.reindex
,而只能使用MyModel.reindex!
。 reindex
方法使用臨時索引來執行原子重新索引:如果使用它,產生的索引將僅包含當前模型的記錄,因為它不會重新索引其他模型。
您可以使用add_index
方法在多個索引中索引記錄:
class Book < ActiveRecord :: Base
attr_protected
include AlgoliaSearch
PUBLIC_INDEX_NAME = "Book_ #{ Rails . env } "
SECURED_INDEX_NAME = "SecuredBook_ #{ Rails . env } "
# store all books in index 'SECURED_INDEX_NAME'
algoliasearch index_name : SECURED_INDEX_NAME do
searchableAttributes [ :name , :author ]
# convert security to tags
tags do
[ released ? 'public' : 'private' , premium ? 'premium' : 'standard' ]
end
# store all 'public' (released and not premium) books in index 'PUBLIC_INDEX_NAME'
add_index PUBLIC_INDEX_NAME , if : :public? do
searchableAttributes [ :name , :author ]
end
end
private
def public?
released && ! premium
end
end
要使用額外索引進行搜索,請使用以下程式碼:
Book . raw_search 'foo bar' , index : 'Book_by_editor'
# or
Book . search 'foo bar' , index : 'Book_by_editor'
若要執行規範,請設定ALGOLIA_APPLICATION_ID
和ALGOLIA_API_KEY
環境變數。由於測試正在建立和刪除索引,因此請勿使用您的生產帳戶。
您可能想要停用所有索引(新增、更新和刪除操作)API 調用,您可以設定disable_indexing
選項:
class User < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch per_environment : true , disable_indexing : Rails . env . test? do
end
end
class User < ActiveRecord :: Base
include AlgoliaSearch
algoliasearch per_environment : true , disable_indexing : Proc . new { Rails . env . test? || more_complex_condition } do
end
end
遇到問題?在尋求支援之前,我們建議先查看我們的常見問題解答,您可以在其中找到最常見問題和客戶遇到的問題的答案。
如果您想為該專案做出貢獻而不安裝其所有依賴項,您可以使用我們的 Docker 映像。請查看我們的專用指南以了解更多資訊。