在PL / pgSQL中按不同类别进行高性能KNN搜索

时间:2018-12-13 17:50:46

标签: postgresql postgis plpgsql knn distinct-on

对于我的硕士论文,我正在分析几种可能对移动服务提供商有用的算法(测试数据集基于移动音乐学校),以寻找一名新学生的最佳老师,以该老师的现有学生为基地考虑在内。

所附代码为简单的KNN(k最近邻)搜索提供了正确的结果,避免了重复。

由于“ DISTINCT ON”要求将st.teacher_id包含在ORDER BY子句中,因此不使用我在几何列“ address_transform”上具有的R-Tree-Index。一旦表的大小变大(学生表为10万行),几何形状变得更复杂等,这将导致非常糟糕的性能。

有什么想法如何重写函数以便使用索引?

CREATE OR REPLACE FUNCTION thesis_knn_distinct (q_neighbors_no integer, q_latitude numeric, q_longitude numeric, q_instrument text, q_student_table character varying)
RETURNS TABLE (
student_id TEXT,
teacher_id TEXT,
distance DOUBLE PRECISION,
instrument TEXT[]
)
AS $$
DECLARE
    location_txt varchar(50) := 'SRID=4326;POINT('||q_longitude||' '||q_latitude||')';
    teacher_table varchar(25);
BEGIN
    IF q_student_table LIKE 'student_hesse%' THEN
        teacher_table = 'teacher_synth_large';
    ELSIF [...]
    END IF;
RETURN QUERY EXECUTE 'WITH teacher_filter AS (
    SELECT DISTINCT ON (st.teacher_id) st.id, st.teacher_id, ST_DistanceSphere(address_box, $2::geometry) AS distance, te.instrument 
        FROM '|| q_student_table::regclass ||' st INNER JOIN '|| teacher_table::regclass ||' te 
        ON st.teacher_id = te.id 
        WHERE te.instrument @> ARRAY[$1]::text[] 
        ORDER BY st.teacher_id, st.address_transform <-> ST_Transform($2::geometry,3857)
    )   
    SELECT * FROM teacher_filter 
        ORDER BY distance
        LIMIT $3;'
    USING q_instrument, location_txt, q_neighbors_no;       
END; $$

LANGUAGE 'plpgsql';

注释:

  • 我正在使用动态查询,因为我正在测试多个真实/合成数据表(索引,非索引,集群等)

  • 我知道可以设置诸如enable_seqscan这样的配置参数,但这并不是解决我的问题的永久方法

  • 作为替代方案,我已经实现了一个(相当快的)变体,其中我通过简单的KNN预选了多个所需的邻居,然后在第二步中删除了重复项。对于纯与距离相关的方法,这行之有效,但如果在随后的步骤中也考虑了除距离以外的其他参数,则预选不一定包含最佳匹配。

  • 我正在使用postgres 10.4,postgis 2.4.4

0 个答案:

没有答案