【问题标题】:Using Ecto for Postgres fulltext search on GIN indexes使用 Ecto 对 GIN 索引进行 Postgres 全文搜索
【发布时间】:2016-09-16 06:43:05
【问题描述】:

我有一个简单的模型:

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

我的搜索功能有问题吗?

【问题讨论】:

  • 您是否在控制台中记录了任何错误?我似乎无法在 PostgreSQL 文档中找到 %WHERE (t0."name" % $1) 中的含义。
  • @Dogbert 没有错误,只是正确的 SQL 命令输出。我从这篇文章中得到了命令:blog.rokkincat.com/postgres-full-text-search-in-ecto
  • 表中有哪些记录?请注意,您的查询不会匹配名称包含 a 的每条记录,而是名称非常相似的记录。尝试创建名称为 "a" 的记录并运行相同的查询。或创建"ab""abc" 并搜索"ab"

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


【解决方案1】:

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

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

set_limit 选项可能有点麻烦,因为每次都需要为每个连接设置它。 Ecto(通过 db_connection)可以选择为after_connect(文档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

首先,我会尝试将限制设为零,看看是否有任何结果。

【讨论】:

  • 函数签名应该改为:def search(query, search_term, limit \\ 0) ?
  • 搜索大约需要 2 秒,这正常吗?不应该快很多吗?我有大约 150 万条记录。
  • 如果您使用 0 的限制和匹配许多行的 search_term,它将必须对所有这些行(可能是数十万甚至数百万)进行排序,这可能不会很快.
猜你喜欢
  • 2013-01-24
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 2016-08-04
  • 1970-01-01
  • 2017-12-09
  • 1970-01-01
  • 2015-09-21
相关资源
最近更新 更多