У меня есть приложение с довольно большим активным набором данных (скажем, автомобилей) с около 2 миллионами активных строк данных.Каждый "автомобиль" имеет множество атрибутов (столбцов), таких как цена, пробег, год, марка, модель, тип топлива и т. Д. И т. Д.
Теперь на странице / show для каждого автомобиля в моем веб-приложении, которое мне нужносоставить список топ-10 самых «похожих» автомобилей.Поскольку я никогда не «знаю», является ли автомобиль очень распространенным или очень редким видом автомобиля (перед тем, как фактически делать запрос БД), я разработал шаблон, в котором я почти не выполняю фильтрацию (WHERE
-классы) в «похожихавтомобили "-query.Вместо этого я делаю много ORDER BY
-предложений в сочетании с CASE WHEN
-проверками, основанными на текущем автомобиле в данных представления.Допустим, пользователь смотрит на Ford Focus, 2010, 30.000km, Gasoline, 12490EUR from around Düsseldorf
машину.Тогда я бы сделал что-то вроде:
SELECT "cars".*
FROM de."cars"
WHERE ("cars"."id" != 24352543)
AND "cars"."sales_state" = 'onsale'
AND (cars.is_disabled IS NOT TRUE)
ORDER BY
CASE WHEN ABS(cars.price - 12490) < cars.price * 0.2 THEN 1 WHEN ABS(cars.price - 12490) < cars.price * 0.4 THEN 2 WHEN ABS(cars.price - 12490) < cars.price * 0.6 THEN 3 ELSE 4 END,
CASE WHEN fuel_type = 'Gasoline' THEN 0 ELSE 1 END,
ABS(cars.price - 12490),
CASE WHEN ST_Distance( ST_GeographyFromText( 'SRID=4326;POINT(' || cars.longitude || ' ' || cars.latitude || ')' ), ST_GeographyFromText('SRID=4326;POINT(12.172130 48.162990)') ) <= 30000 THEN 1 WHEN ST_Distance( ST_GeographyFromText( 'SRID=4326;POINT(' || cars.longitude || ' ' || cars.latitude || ')' ), ST_GeographyFromText('SRID=4326;POINT(12.172130 48.162990)') ) <= 100000 THEN 2 ELSE 3 END,
ABS(cars.year - 2010),
ABS(cars.km - 30000)
LIMIT 10
На самом деле есть еще больше пунктов заказа.
Теперь это удобно, потому что неважно, насколько «легко» найти 10 «релевантных»автомобили, похожие на нынешнюю машину, запрос всегда будет возвращать что-то - проблема в том, что он медленный и практически невозможно проиндексировать, насколько мне известно.Делая это на 2 миллионах записей, даже если у меня есть суперскоростный суперскоростной выделенный PostgreSQL 11, 300 ГБ оперативной памяти, 10 SSD RAID 10 32 основных сервера, это все равно займет у меня около 2-4 секунд, времени у меня нет.Мне нужно это до <200 мс. </p>
Я ломал голову над подходами к решению этой проблемы, но, поскольку у меня нет опыта решения таких проблем в масштабе, я не уверен, какой подход окупится лучше,решение проблемы.Некоторые из идей, которые у меня есть:
- Выполнение запроса итеративным способом, где я фильтрую (
WHERE
) по некоторому столбцу в терминах (например, начиная с ограничения данных на подмножестве цен), чтобы уменьшить набор данных.Затем, если результаты будут возвращены, отлично, в противном случае сделайте еще один немного более широкий запрос и т. Д. И т. Д. - Используя совершенно другой тип алгоритма, возможно, предварительно заполняя какие-то столбцы показателей сходства для автомобилей
- Использование некоторых внутренних возможностей / расширений PostgreSQL, которые могут ускорить процесс, какими бы они ни были?