Как рассчитать наиболее популярную комбинацию строк заказа? (или любое подобное расположение БД ордер/строки ордеров)
Я использую Ruby on Rails. У меня есть пара моделей, которые соответствуют нормальному порядку / порядку линий, т. е.
class Order
has_many :order_lines
end
class OrderLines
belongs_to :order
belongs_to :product
end
class Product
has_many :order_lines
end
(значительно упрощено по сравнению с моей реальной моделью!)
Довольно просто вычислить наиболее популярные отдельные продукты через строку заказа, но какой волшебный ruby-fu я мог бы использовать для вычисления самой популярной комбинации(ов) заказанных продуктов.
Ура!, Грэм
2 ответа:
Мое предложение состоит в том, чтобы создать массив a из
Product.id
чисел для каждого порядка, а затем сделать эквивалентВам, естественно, нужно будет рассмотреть масштаб вашей операции и насколько вы готовы приблизить результаты.h = Hash.new(0) # for each a h[a.sort.hash] += 1
Внешнее Решение
Создайте "комбинационную" модель и проиндексируйте таблицу по хэшу,после чего каждый ордер может увеличить поле счетчика. Другое поле будет точно записывать, на какую комбинацию ссылается это хэш-значение к.
решение в памяти
Посмотрите на последние 100 заказов и пересчитайте популярность заказа в памяти, когда вам это нужно.Hash#sort
даст вам упорядоченный список хэшей популярности. Вы можете либо создать составной объект, который помнит, какая комбинация порядка была подсчитана, либо просто сканировать исходные данные в поисках хэш-значения.
Спасибо за подсказку digitalross. Я последовал идее внешнего решения и сделал следующее. Он немного отличается от предложения, поскольку он хранит запись отдельных order_combos, а не хранит счетчик, так что можно запросить по дате, например, самые популярные топ-10 заказов на прошлой неделе.
Я создал метод в своем заказе, который преобразует список элементов заказа в строку, разделенную запятыми.
def to_s order_lines.sort.map { |ol| ol.id }.join(",") end
Затем я добавил фильтр, чтобы комбо создавалось каждый раз, когда заказ сделан.
after_save :create_order_combo def create_order_combo oc = OrderCombo.create(:user => user, :combo => self.to_s) end
И, наконец, мой класс OrderCombo выглядит примерно так, как показано ниже. Я также включил кэшированную версию метода.
class OrderCombo belongs_to :user scope :by_user, lambda{ |user| where(:user_id => user.id) } def self.top_n_orders_by_user(user,count=10) OrderCombo.by_user(user).count(:group => :combo).sort { |a,b| a[1] <=> b[1] }.reverse[0..count-1] end def self.cached_top_orders_by_user(user,count=10) Rails.cache.fetch("order_combo_#{user.id.to_s}_#{count.to_s}", :expiry => 10.minutes) { OrderCombo.top_n_orders_by_user(user, count) } end end
Это не идеально, так как не учитывает возросшую популярность, когда кто-то заказывает больше одного предмета в заказе.