2016-09-16 68 views
0

我有一個簡單的模型:使用外生對GIN索引Postgres的全文搜索

schema "torrents" do 
    field :name, :string 
    field :magnet, :string 
    field :leechers, :integer 
    field :seeders, :integer 
    field :source, :string 
    field :filesize, :string 

    timestamps() 
end 

而且我要根據名稱進行搜索。我將相關的擴展和索引添加到我的數據庫和表中。

def change do 
    create table(:torrents) do 
    add :name, :string 
    add :magnet, :text 
    add :leechers, :integer 
    add :seeders, :integer 
    add :source, :string 
    add :filesize, :string 

    timestamps() 
    end 

    execute "CREATE EXTENSION pg_trgm;" 
    execute "CREATE INDEX torrents_name_trgm_index ON torrents USING gin (name gin_trgm_ops);" 

    create index(:torrents, [:magnet], unique: true) 
end 

我嘗試使用搜索詞,搜索,但我總是得到結果爲零

def search(query, search_term) do 
    from(u in query, 
    where: fragment("? % ?", u.name, ^search_term), 
    order_by: fragment("similarity(?, ?) DESC", u.name, ^search_term)) 
end 

SELECT t0."id", t0."name", t0."magnet", t0."leechers", t0."seeders", t0."source", 
t0."filesize", t0."inserted_at", t0."updated_at" FROM "torrents" 
AS t0 WHERE (t0."name" % $1) ORDER BY similarity(t0."name", $2) DESC ["a", "a"] 

我的搜索功能有問題嗎?

+0

您是否在控制檯中記錄了任何錯誤?我似乎無法在PostgreSQL文檔中找到'%'在'WHERE(t0。「name」%$ 1)'中的含義。 – Dogbert

+0

@Dogbert沒有錯誤,只是正確的SQL命令輸出。我得到了這篇文章中的命令:http://blog.rokkincat.com/postgres-full-text-search-in-ecto/ –

+0

你在桌上有什麼記錄?請注意,您的查詢不會匹配每個名稱包含'a'但記錄的名稱足夠相似的記錄。嘗試創建一個名稱爲「」a「的記錄並運行相同的查詢。或者創建''ab「'和'」abc「'並搜索'」ab「'。 – Dogbert

回答

1

我最初的猜測是,因爲您使用的是%運算符,所以查詢的最小匹配限制太高。此限制默認爲0.3(表示字符串的三元組相似度爲30%)。如果不符合此閾值,則不會返回任何結果。

如果這是問題,則可以通過幾種方法配置此閾值。您可以使用set_limit(文檔here),或者設置每個查詢的限制。

set_limit選項可能有點麻煩,因爲它需要每次連接設置。 Ecto(通過db_connection)可以爲after_connect(docs here)設置回調函數。

要更改每個查詢的限制,您可以使用​​函數在where子句中,像這樣的:

def search(query, search_term, limit = 0.3) do 
    from(u in query, 
    where: fragment("similarity(?, ?) > ?", u.name, ^search_term, ^limit), 
    order_by: fragment("similarity(?, ?) DESC", u.name, ^search_term)) 
end 

首先,我會嘗試爲零的極限,看看你得到任何結果。

+0

函數簽名應該改爲:'def search(query,search_term,limit \\ 0)'? –

+0

搜索大約需要2秒鐘,這是正常的嗎?它不應該更快?我有大約150萬條記錄。 –

+0

如果使用匹配多行的'search_term'的限制爲0,則必須對所有這些行進行排序(可能有數十萬甚至上百萬),這可能不夠快。 – mitchellhenke