Статьи

Neo4j: первая попытка замены розничного продукта

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

Так как эта проблема объединяет три типа данных — историю заказов, уровень запасов и продукты — кажется, что она должна хорошо подходить для Neo4j, поэтому я привел короткий пример.

Я написал следующий шифр, чтобы создать некоторые продукты, человека, несколько заказов и затем доступность этих продуктов в воображаемом магазине.

CREATE (bakedBeans :Category {name: "Baked Beans"} )
CREATE (fruit :Category {name: "Fruit"} )
 
CREATE (hbb :Product {name: "Heinz Baked Beans", type: "brand"} )
CREATE (bbb :Product {name: "Branstone Baked Beans", type: "brand"} )
CREATE (sbb :Product {name: "Sainsbury's Baked Beans", type: "own"} )
CREATE (apple :Product {name: "Bag of Apples"} )
 
CREATE UNIQUE (hbb)-[:HAS_CATEGORY]->(bakedBeans)
CREATE UNIQUE (bbb)-[:HAS_CATEGORY]->(bakedBeans)
CREATE UNIQUE (sbb)-[:HAS_CATEGORY]->(bakedBeans)
 
CREATE (southwark :Store {name: "Southwark"})
 
CREATE UNIQUE (southwark)-[:HAS_IN_STOCK {availability: 0}]->(hbb)
CREATE UNIQUE (southwark)-[:HAS_IN_STOCK {availability: 2}]->(bbb)
CREATE UNIQUE (southwark)-[:HAS_IN_STOCK {availability: 10}]->(sbb)
CREATE UNIQUE (southwark)-[:HAS_IN_STOCK {availability: 10}]->(apple)
 
CREATE (mark :Person {name: "Mark"})
 
CREATE (order1 :Order {id: 1, date: 1380884632})
 
CREATE UNIQUE (order1)-[:CONTAINS {count: 1}]->(hbb)
CREATE UNIQUE (order1)-[:CONTAINS {count: 5}]->(apple)
CREATE UNIQUE (mark)-[:PLACED_ORDER]->(order1)
 
CREATE (order2 :Order {id: 2, date: 1380885051})
 
CREATE UNIQUE (order2)-[:CONTAINS {count: 1}]->bbb
CREATE UNIQUE (mark)-[:PLACED_ORDER]->(order2)

Затем у нас может быть новый заказ, который мы пытаемся выполнить, и мы хотим проверить, есть ли продукты в наличии.

Сначала мы создадим заказ:

// Create the order
CREATE (order3:Order {id: 3, date: 1380895051})
 
WITH order3
 
// Assign the order to Mark
MATCH (p:Person)
WHERE p.name = "Mark"
CREATE UNIQUE (p)-[:PLACED_ORDER]->(order3)
 
WITH order3
 
// Populate the order with some products
MATCH (p:Product)
WHERE p.name = "Heinz Baked Beans" 
CREATE UNIQUE (order3)-[:CONTAINS {count: 2}]->(p)
 
WITH order3
 
MATCH (p:Product)
WHERE p.name = "Bag of Apples"
CREATE UNIQUE (order3)-[:CONTAINS {count: 2}]->(p)

Теперь давайте проверим наличие каждого товара в заказе в конкретном магазине:

// Find the products in the order
MATCH (o:Order)-[c:CONTAINS]->(product)
WHERE o.id = 3
WITH product, c.count AS count
 
// Check which items are out of stock in our store
MATCH (s:Store)-[inStock:HAS_IN_STOCK]->(product)
WHERE s.name = "Southwark"
RETURN product, inStock
 
==> +--------------------------------------------------------------------------------------------+
==> | product                                            | inStock                               |
==> +--------------------------------------------------------------------------------------------+
==> | Node[11444]{name:"Heinz Baked Beans",type:"brand"} | :HAS_IN_STOCK[60053]{availability:0}  |
==> | Node[11447]{name:"Bag of Apples"}                  | :HAS_IN_STOCK[60056]{availability:10} |
==> +--------------------------------------------------------------------------------------------+

Теперь, если мы изменим этот запрос, чтобы вернуть только те товары, у которых на складе меньше товаров, чем мы пытались заказать, мы увидим, что Запеченные бобы Heinz недоступны:

// Find the products in the order
MATCH (o:Order)-[c:CONTAINS]->(product)
WHERE o.id = 3
WITH product, c.count AS count
 
// Check which items are out of stock in our store
MATCH (s:Store)-[inStock:HAS_IN_STOCK]->(product)
WHERE s.name = "Southwark" AND count > inStock.availability
RETURN product, inStock
 
==> +-------------------------------------------------------------------------------------------+
==> | product                                            | inStock                              |
==> +-------------------------------------------------------------------------------------------+
==> | Node[15281]{name:"Heinz Baked Beans",type:"brand"} | :HAS_IN_STOCK[86079]{availability:0} |
==> +-------------------------------------------------------------------------------------------+
MATCH (p:Person)-[:PLACED_ORDER]->order-[c:CONTAINS]->product-[:HAS_CATEGORY]->category
WHERE p.name = "Mark" AND category.name = "Baked Beans" AND order.id <> 3
RETURN product.name, product.type, order.id
 
==> +---------------------------------------------------+
==> | product.name            | product.type | order.id |
==> +---------------------------------------------------+
==> | "Heinz Baked Beans"     | "brand"      | 1        |
==> | "Branstone Baked Beans" | "brand"      | 2        |
==> +---------------------------------------------------+

Определив Марка как ценителя запеченных бобов под маркой, мы могли бы затем выполнить запрос, чтобы проверить, есть ли в этом магазине другие запеченные бобы под маркой:

MATCH (s:Store)-[inStock:HAS_IN_STOCK]->p-[:HAS_CATEGORY]->c
WHERE s.name = "Southwark" 
AND c.name = "Baked Beans" 
AND inStock.availability > 0 
AND p.type = "brand"
RETURN p.name, inStock.availability
 
==> +------------------------------------------------+
==> | p.name                  | inStock.availability |
==> +------------------------------------------------+
==> | "Branstone Baked Beans" | 2                    |
==> +------------------------------------------------+

Это, очевидно, чрезвычайно наивный подход, поэтому я отправился в твиттер в надежде найти более сложный подход:

Николь Уайт в настоящее время играет с майнингом правил ассоциации, что звучит интересно.

Это описано на его странице в Википедии примерно так:

Основываясь на концепции строгих правил, Ракеш Агравал и др. [2] ввел правила ассоциации для выявления закономерностей между продуктами в крупномасштабных данных о транзакциях, зарегистрированных в торговых точках (POS) в супермаркетах.

Хотя это не совсем то, что я хочу сделать, мне нужно больше посмотреть на это, чтобы увидеть, можно ли применить некоторые идеи.

Я также узнал, что терминология для того, что я ищу, — это алгоритм « похожих предметов », и я думаю, что я хотел бы увидеть гибридную систему рекомендаций, которая сочетает в себе сходство контента и предыдущую историю покупок пользователя.

Я искал вокруг, чтобы посмотреть, есть ли какие-нибудь открытые или анонимные розничные наборы данных, с которыми можно поиграться, но все, с чем я столкнулся, это « Репозиторий наборов данных для частых наборов ». К сожалению, когда я пытался открыть файлы, они, кажется, просто содержат случайные числа, поэтому я, должно быть, делал что-то не так.

Если кто-нибудь знает о наборе данных о розничной торговле, с которым я могу поиграть, пожалуйста, укажите мне правильное направление.