2016-09-16 98 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