Как найти «похожие» заказы на основе номера артикула

#php #laravel #postgresql #data-warehouse

#php #laravel #postgresql #хранилище данных

Вопрос:

Итак, я бьюсь головой уже несколько дней… Я должен каким-то образом найти «похожий» заказ на основе элементов начального заказа SKU и сгруппировать их в партии по 20 слотов * 40 кг в каждом слоте, так что в общей сложности 800 кг макс.

У меня есть две таблицы orders и order_items. Таблица заказов содержит идентификатор и идентификатор магазина и некоторые временные метки. Таблица элементов заказа содержит order_id, артикул, количество и объем / вес.

Я использую Laravel 8. *, PHP 7.4 и Postgres

Что я уже пробовал:

Получение начального заказа, который является самым старым в пуле заказов, найденных конкретной группой пакетов, которая выглядит следующим образом

 //The batch group query

if (!empty($batchGroup->group['carriers'])) {
            $this->whereIn('carrier', $batchGroup->group['carriers']);
        }

        if (!empty($batchGroup->group['methods'])) {
            $this->whereIn('method', $batchGroup->group['methods']);
        }

        if (!empty($batchGroup->group['countries'])) {
            foreach ($batchGroup->group['countries'] as $k => $country) {
                if ($k === 0) {
                    $this->where('country', '=', $country);
                } else {
                    $this->where('country', '=', $country, 'or');
                }
            }
        }
  

После этого я получаю артикулы этого заказа, делая это:

 $seedItemsSku = $seedOrder->items->pluck('sku')->toArray();

//Here i have array with SKUS: [102312, 150021, 125125] etc...
  

Здесь начинается самое интересное…

Я создал функцию в построителе запросов, которая должна возвращать все совпадающие заказы

 public function similar(Order $seedOrder, BatchGroup $batchGroup, array $exceptOrders = []): self
    {
        $skus = $seedOrder->items->pluck('sku')->toArray();

        $query = $this;

        if (!empty($exceptOrders)) {
            $query->whereNotIn('id', $exceptOrders);
        }
        return $this->whereHas('items', function (OrderItemQueryBuilder $builder) use ($skus) {
                $builder->whereIn('sku', $skus);
            })
            ->whereNull('batch_id')
            ->where('total_weight', '<=', 200);
    }
  

Проблема с приведенной выше функцией заключается в том, что она получает результат, который со смешанными артикулами не СОВСЕМ соответствует начальным артикулам. Кроме того, это очень медленно.

Я ищу способ / совет, как я могу достичь этого результата.

Вот сценарий: магазин получил 5 тыс. заказов за ночь. Они должны быть упакованы на следующий день. Система получает самый старый заказ, берет артикулы и начинает искать похожие заказы, 100% совпадение артикулов будет идеальным. Но если у нас есть заказ с этим артикулом и еще один, которого нет в начальном заказе, у нас снова совпадение. Цель состоит в том, чтобы добиться максимальной эффективности партии и избежать обхода большого склада для 5 заказов. Кроме того, товары на складе имеют местоположение, по которому я буду сортировать конечный результат по ячейкам партии.

IMO, это странная логика, но именно так работает клиент, и сборщики / упаковщики привыкли.

ОБНОВЛЕНИЕ: это запрос, который должен находить похожие заказы.

 SELECT
    id, country, total_items, total_weight, batch_id
FROM
    "orders"
WHERE
    EXISTS (
        SELECT
            *
        FROM
            "order_items"
        WHERE
            "orders"."id" = "order_items"."order_id"
            AND "sku" in('104026')
            AND "order_items"."deleted_at" IS NULL)
        AND "country" = 'Germany'
        AND "orders"."deleted_at" IS NULL
  

Это результат:

Результат запроса

Комментарии:

1. Я не понимаю, как whereIn создается нечеткое совпадение по артикулам. Это строгое сравнение в том смысле, что значение sku должно существовать в массиве $skus .

2. Он соответствует хотя бы одному, но возвращает результат с другим артикулом в порядке, а не только с выбранными