2014-12-30 3 views
0

Мы пытались создать онлайн-рекомендацию (совместную фильтрацию пользователя-пользователя) с использованием сходства косинусов с данными в Neo4j.Neo4j Рекомендатор Двигатель (Предпочтение)

** Разница заключалась в том, что набор входных данных является булевым предпочтением (в отличие от рейтинга) ** для 1 млн пользователей X ~ 700 продуктов. например. User_ID, PRODUCT_ID, Предпочтение 11,48989399,1

создания узлов для пользователей и продуктов с индексом по идентификатору (user_id, product_id)

Я пытался писать Cypher запрос, чтобы получить лучшие 20 ближайших соседей на основе формула

Сходство = (продукты понравившиеся как пользователями)/SQRT (# продуктов нравится user1) * SQRT (# продуктов нравится user2)

Ниже приведен запрос:

MATCH (a:Users)-[d]->() using index a:Users(id) where a.id =1 
WITH a.id as user1, count(d) as user1_prod 
MATCH (a:Users)-[]->()<-[dd]-others using index a:Users(id) where a.id =1 
WITH user1, user1_prod, others, count(dd) as intersect 
MATCH others-[b1]->() with user1, others.id as user2, intersect, user1_prod, count(b1) as user2_prod 
WITH user1, user2, intersect/(sqrt(user1_prod) * sqrt(user2_prod)) as similarity 
RETURN user2, similarity order by similarity desc limit 20;  

Запрос возвращает результаты в течение примерно 22 секунд после того, как рекомендации продуктов будут масштабируемыми и быстрыми.

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

Детали: Ядро версии Neo4j - База данных Graph Ядро (Neo4j-ядро), версия: 2.1.6

772 772 узлов

neostore.relationshipstore.db.mapped_memory 3078M

CentOS релиз 6.6 (Final)

ответ

0

Это будет намного быстрее, если вы перепишете его как расширение сервера Neo4j, тогда вы можете использовать node.getDegree(), который является постоянным поиском по времени o f - степень узла.

Ключевой код будет выглядеть так, вы можете упростить его, извлекая функцию для получения продуктов на пользователя.

Node user1 = db.findByLabelAndProperty(User,"id",1); 
long likes1 = user1.getDegree(LIKES,OUTGOING); 
Set<Node> products1 = new HashSet<>(likes1); 
for (Relationship rel = user1.getRelationships(LIKES,OUTGOING)) { 
    products1.add(rel.getEndNode()); 
} 

Node user2 = db.findByLabelAndProperty(User,"id",2); 
long likes2 = user2.getDegree(LIKES,OUTGOING); 
Set<Node> products2 = new HashSet<>(likes2); 
for (Relationship rel = user2.getRelationships(LIKES,OUTGOING)) { 
    products2.add(rel.getEndNode()); 
} 

products1.retainAll(products2); 

return products1.size()/(sqrt(likes1) * sqrt(likes2)); 
+0

Спасибо, Майкл, я попытаюсь вернуться к исходному результату. – VishalK

Смежные вопросы