You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将自定义distance/2函数作为Ecto order_by/3的参数?

解决Ecto Query中使用自定义编辑距离函数排序的问题

你遇到的核心问题是:Ecto Query需要转换为SQL在数据库执行,直接在order_by中使用Elixir自定义的distance/2函数行不通——数据库无法识别Elixir函数;而第二种写法里的p是Ecto Query上下文内的绑定变量,在Query宏外部调用distance(p.name, term)时,外部环境根本找不到p,所以报错。

以下是具体解决方法:

方法1:直接使用数据库内置编辑距离函数(推荐)

主流数据库大多内置了编辑距离相关函数,直接复用即可避免自定义SQL的麻烦:

  • PostgreSQL:使用levenshtein函数(需先安装fuzzystrmatch扩展)
  • MySQL:使用LEVENSHTEIN函数(需安装mysql-udf-fuzzy扩展)
  • SQLite:使用editdistance函数(需加载对应扩展)

以PostgreSQL为例,先确保数据库安装扩展:

CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;

之后在Ecto Query中通过fragment调用该SQL函数:

Api.Repo.all(
  from p in Api.Product,
  select: p.name,
  order_by: fragment("levenshtein(?, ?)", p.name, ^term),
  where: p.company_id == ^company_id
)

方法2:自定义Ecto SQL函数映射

如果数据库无内置函数,或你需要复用自己的编辑距离逻辑,可以将Elixir函数映射为数据库可执行的SQL函数:

  1. 在数据库中创建对应的SQL函数(以PostgreSQL为例):
CREATE OR REPLACE FUNCTION distance(a text, b text)
RETURNS integer AS $$
DECLARE
  len_a integer;
  len_b integer;
  matrix integer[][];
BEGIN
  len_a := length(a);
  len_b := length(b);
  
  IF len_a = 0 THEN RETURN len_b; END IF;
  IF len_b = 0 THEN RETURN len_a; END IF;
  
  matrix := array_fill(0, ARRAY[len_a + 1, len_b + 1]);
  
  FOR i IN 0..len_a LOOP matrix[i+1][1] := i; END LOOP;
  FOR j IN 0..len_b LOOP matrix[1][j+1] := j; END LOOP;
  
  FOR i IN 1..len_a LOOP
    FOR j IN 1..len_b LOOP
      matrix[i+1][j+1] := LEAST(
        matrix[i][j+1] + 1,
        matrix[i+1][j] + 1,
        matrix[i][j] + CASE WHEN substring(a from i for 1) = substring(b from j for 1) THEN 0 ELSE 1 END
      );
    END LOOP;
  END LOOP;
  
  RETURN matrix[len_a + 1][len_b + 1];
END;
$$ LANGUAGE plpgsql;
  1. 在Elixir代码中定义Ecto自定义函数:
defmodule Api.Distance do
  import Ecto.Query, only: [fragment: 1]

  def distance(a, b) do
    fragment("distance(?, ?)", a, b)
  end
end
  1. 在Query中调用该自定义函数:
import Api.Distance

Api.Repo.all(
  from p in Api.Product,
  select: p.name,
  order_by: distance(p.name, ^term),
  where: p.company_id == ^company_id
)

内容的提问来源于stack exchange,提问作者Basil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:05:25