📜  项目理念 |基于图数据库的推荐系统(1)

📅  最后修改于: 2023-12-03 15:12:52.363000             🧑  作者: Mango

项目理念 | 基于图数据库的推荐系统

介绍

本项目基于图数据库实现了一个推荐系统,主要功能是根据用户的兴趣爱好和历史行为,推荐给用户相似的内容。推荐系统是现代互联网业务中的核心应用之一,可以用于电商平台、社交网络、影视娱乐等领域。

在传统的关系型数据库中,推荐系统主要是通过建立用户-物品的关系矩阵,运用协同过滤、矩阵分解等算法实现的。但是,经典的推荐算法往往只考虑了单一的因素,比如用户和物品之间的相似度,而忽略了更复杂的因素和关系,比如用户群体和物品类别等。这些复杂因素和关系无法用简单的结构来表达和存储,因此图数据库应运而生。

技术栈

本项目所采用的技术栈如下:

  • Python 3.x: 开发语言
  • Neo4j: 图数据库
  • Flask: Web框架
  • jQuery: 前端框架
项目架构

该推荐系统主要由四个部分组成:

数据库

本项目使用了图数据库Neo4j来存储数据。与传统的关系型数据库不同,Neo4j采用了图论的思想,将数据存储为节点和边的形式。本项目将用户、物品、标签等信息存储在图数据库中,用节点表示不同的实体,用边表示它们之间的关系。

数据获取

数据获取模块主要负责从MySQL数据库中获取用户和物品信息,根据不同的规则构建出图数据库中的节点和边,更新图数据库中的数据。

推荐算法

推荐算法模块采用了基于图的推荐算法,主要包括以下几个步骤:

  1. 根据用户的兴趣爱好,查找出用户所感兴趣的物品类别。
  2. 在物品节点中查找与目标用户的兴趣爱好最相似的物品,就是我们要为用户推荐的物品。
  3. 将推荐物品与目标用户的兴趣爱好之间建立边,为后续推荐算法提供数据基础。
推荐服务

推荐服务模块向前端提供推荐数据,用户通过前端页面进行交互,将推荐结果展示出来。

代码片段

以下是部分代码片段,完整代码请见https://github.com/xxx/xxx

# 数据库连接
from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))

# 推荐算法
def recommend(userId):
    session = driver.session()

    # 找出用户感兴趣的物品类别
    interestTags = session.run('MATCH (user:User)-[:LIKE]->(tag:Tag) '
                               'WHERE user.id=$userId '
                               'RETURN tag.name AS tagName', userId=userId)

    recommendItems = []

    for interestTag in interestTags:
        tagName = interestTag['tagName']

        # 找出所有包含该物品类别的物品
        items = session.run('MATCH (item:Item)-[:HAS]->(tag:Tag) '
                            'WHERE tag.name=$tagName '
                            'RETURN item', tagName=tagName)

        for item in items:
            itemId = item['item']['id']

            # 找出用户和该物品之间的联系程度
            relation = session.run('MATCH (user:User)-[r:SIMILARITY]-(item:Item) '
                                   'WHERE user.id=$userId AND item.id=$itemId '
                                   'RETURN r.similarity AS similarity', userId=userId, itemId=itemId).single()

            if relation is None:
                # 如果用户和该物品没有联系,就建立一条联系
                session.run('MATCH (user:User), (item:Item) '
                            'WHERE user.id=$userId AND item.id=$itemId '
                            'CREATE (user)-[:SIMILARITY {similarity:1.0}]->(item)', userId=userId, itemId=itemId)

            elif relation['similarity'] < 1.0:
                # 如果用户和该物品的联系程度小于1,就更新联系
                session.run('MATCH (user:User)-[r:SIMILARITY]-(item:Item) '
                            'WHERE user.id=$userId AND item.id=$itemId '
                            'SET r.similarity=$similarity', userId=userId, itemId=itemId, similarity=relation['similarity']+0.1)

            # 将推荐物品和用户之间建立边
            session.run('MATCH (user:User), (item:Item) '
                        'WHERE user.id=$userId AND item.id=$itemId '
                        'CREATE (user)-[:RECOMMEND]->(item)', userId=userId, itemId=itemId)

            if itemId not in recommendItems:
                # 如果该物品还没有被推荐过,就加入待推荐列表
                recommendItems.append(itemId)

    # 找出待推荐物品的详细信息
    result = []
    for itemId in recommendItems:
        item = session.run('MATCH (item:Item) '
                           'WHERE item.id=$itemId '
                           'RETURN item', itemId=itemId).single()

        result.append(item['item'])

    session.close()

    return result
<!-- 前端页面 -->
<div id="recommend-list">
    <ul>
        <li v-for="item in recommendItems">
            <div>{{ item.name }}</div>
            <div>{{ item.price }}</div>
            <div>{{ item.description }}</div>
        </li>
    </ul>
</div>

<script>
    // 调用推荐服务
    $.ajax({
        url: '/recommend?userId=1',
        type: 'GET',
        success: function(data) {
            app.recommendItems = data;
        }
    });
</script>