使用Ecto for Postgres全文搜索GIN索引

时间:2016-09-16 06:43:05

标签: postgresql indexing full-text-search elixir ecto

我有一个简单的模型:

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"]

我的搜索功能有问题吗?

1 个答案:

答案 0 :(得分:1)

我最初的猜测是,因为您使用的是%运算符,所以匹配的最小限制对您的查询来说太高了。此限制默认为0.3(意味着字符串的三元组与30%相似)。如果未达到此阈值,则不会返回任何结果。

如果出现问题,可以通过多种方式配置此阈值。您可以使用set_limit(文档here),也可以基于每个查询设置限制。

set_limit选项可能有点麻烦,因为每次都需要为每个连接设置。 Ecto(通过db_connection)可以选择为after_connect设置回调函数(docs here)。

要更改每个查询的限制,您可以在where子句中使用similarity函数,如下所示:

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

首先,我会尝试使用零限制来查看是否有任何结果。