使用 Ecto 对 GIN 索引进行 Postgres 全文搜索
Using Ecto for Postgres fulltext search on GIN indexes
我有一个简单的模型:
schema "torrents" do
field :name, :string
field :magnet, :string
field :leechers, :integer
field :seeders, :integer
field :source, :string
field :filesize, :string
timestamps()
end
而且我想根据名字搜索。我将相关的扩展名和索引添加到我的数据库和 table.
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" % ) ORDER BY similarity(t0."name", ) DESC ["a", "a"]
我的搜索功能有问题吗?
我最初的猜测是因为您使用的是 %
运算符,匹配的最小限制对于您的查询来说太高了。此限制默认为 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
首先,我会尝试以零为限,看看您是否能得到任何结果。
我有一个简单的模型:
schema "torrents" do
field :name, :string
field :magnet, :string
field :leechers, :integer
field :seeders, :integer
field :source, :string
field :filesize, :string
timestamps()
end
而且我想根据名字搜索。我将相关的扩展名和索引添加到我的数据库和 table.
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" % ) ORDER BY similarity(t0."name", ) DESC ["a", "a"]
我的搜索功能有问题吗?
我最初的猜测是因为您使用的是 %
运算符,匹配的最小限制对于您的查询来说太高了。此限制默认为 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
首先,我会尝试以零为限,看看您是否能得到任何结果。