Поиск по KNN по отдельной категории в PL / pgSQL - PullRequest
0 голосов
/ 13 декабря 2018

Для моей магистерской диссертации я анализирую несколько алгоритмов, которые могут быть полезны для оператора мобильной связи (наборы тестовых данных основаны на мобильной музыкальной школе), чтобы найти оптимального учителя для нового ученика, занимающего местоположения существующих учеников учителяв учет.

Прикрепленный код обеспечивает правильные результаты для простого поиска KNN (k-ближайшего соседа), избегая дублирования.

Поскольку "DISTINCT ON" требует, чтобы st.teacher_id был включен в предложение ORDER BY, R-Tree-Index, который у меня есть в моем столбце геометрии "address_transform", не используется.Это приводит к очень плохой производительности, когда размер таблицы увеличивается (100 тыс. Строк для таблицы ученика), геометрия становится более сложной и т. Д.

Есть идеи, как переписать функцию, чтобы индекс использовался?

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

...