Python中使用MongoDB和Elasticsearch进行推荐系统的实现

2023-04-15 00:00:00 python 系统 推荐
  1. MongoDB部分

在MongoDB中,我们需要建立一个集合来存储用户行为数据,并根据这些数据生成用户画像。

首先,我们创建一个名为“user_behavior”的集合,并插入一些用户行为数据:

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["test"]
collection = db["user_behavior"]

data = [
    {"user": "张三", "behavior": "click", "content": "pidancode.com"},
    {"user": "张三", "behavior": "click", "content": "皮蛋编程"},
    {"user": "李四", "behavior": "click", "content": "pidancode.com"},
    {"user": "李四", "behavior": "share", "content": "pidancode.com"},
    {"user": "王五", "behavior": "click", "content": "皮蛋编程"},
]

collection.insert_many(data)

然后,我们可以根据用户行为数据来生成用户画像。在这个例子中,我们使用用户的行为次数来表示用户对不同内容的兴趣:

pipeline = [
    {"$group": {"_id": {"user": "$user", "content": "$content"}, "count": {"$sum": 1}}},
    {"$group": {"_id": "$_id.user", "contents": {"$push": {"content": "$_id.content", "count": "$count"}}}},
    {"$project": {"_id": 0, "user": "$_id", "contents": 1}},
]

result = list(collection.aggregate(pipeline))

for item in result:
    print(item)

输出结果如下:

{'user': '张三', 'contents': [{'content': 'pidancode.com', 'count': 1}, {'content': '皮蛋编程', 'count': 1}]}
{'user': '李四', 'contents': [{'content': 'pidancode.com', 'count': 2}]}
{'user': '王五', 'contents': [{'content': '皮蛋编程', 'count': 1}]}

可以看到,我们成功地根据用户行为数据生成了用户画像。

  1. Elasticsearch部分

在Elasticsearch中,我们需要建立一个索引来存储内容数据,并根据这些数据生成内容画像。

首先,我们创建一个名为“content”的索引,并定义一些字段:

from elasticsearch import Elasticsearch

es = Elasticsearch()

index_name = "content"

settings = {
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0
    },
    "mappings": {
        "properties": {
            "title": {"type": "text"},
            "description": {"type": "text"},
            "tags": {"type": "keyword"},
            "url": {"type": "keyword"}
        }
    }
}

es.indices.create(index_name, body=settings)

然后,我们插入一些内容数据:

data = [
    {"title": "Python编程入门教程", "description": "本课程介绍Python编程的基础知识和应用场景,适合初学者。", "tags": ["Python", "编程"], "url": "www.pidancode.com/python-tutorial"},
    {"title": "Java入门视频教程", "description": "本课程介绍Java编程的基础知识和应用场景,适合初学者。", "tags": ["Java", "编程"], "url": "www.pidancode.com/java-tutorial"},
    {"title": "Docker部署实践", "description": "本文介绍如何使用Docker进行应用部署,包括常用命令和注意事项。", "tags": ["Docker", "应用部署"], "url": "www.pidancode.com/docker-deployment"},
    {"title": "Elasticsearch入门指南", "description": "本文介绍如何使用Elasticsearch进行全文检索和分析,适合初学者。", "tags": ["Elasticsearch", "全文检索"], "url": "www.pidancode.com/elasticsearch-guide"},
]

for item in data:
    es.index(index=index_name, body=item)

接下来,我们可以根据内容数据来生成内容画像。在这个例子中,我们使用标签的出现次数来表示内容的受欢迎程度:

aggs = {
    "tags": {
        "terms": {"field": "tags"}
    }
}

result = es.search(index=index_name, body={"size": 0, "aggs": aggs})

for item in result["aggregations"]["tags"]["buckets"]:
    print(item)

输出结果如下:

{'key': '编程', 'doc_count': 2}
{'key': 'Python', 'doc_count': 1}
{'key': 'Java', 'doc_count': 1}
{'key': '应用部署', 'doc_count': 1}
{'key': 'Docker', 'doc_count': 1}
{'key': '全文检索', 'doc_count': 1}
{'key': 'Elasticsearch', 'doc_count': 1}

可以看到,我们成功地根据内容数据生成了内容画像。

  1. 推荐系统实现

有了用户画像和内容画像,我们就可以通过它们来实现推荐系统了。在这个例子中,我们采用基于内容的推荐算法。具体来说,对于每个用户,我们都计算他们与所有内容的相似度,并按相似度从高到低排序,然后选取前N个推荐给用户。

import math

def cosine_similarity(vec1, vec2):
    dot_product = sum([v1*v2 for v1, v2 in zip(vec1, vec2)])
    norm1 = math.sqrt(sum([v*v for v in vec1]))
    norm2 = math.sqrt(sum([v*v for v in vec2]))
    return dot_product / (norm1 * norm2)

def recommend(user, N):
    # 获取用户画像
    user_profile = next(filter(lambda item: item["user"] == user, result), None)
    if not user_profile:
        return []

    # 计算用户对内容的兴趣度
    interests = {}
    for item in user_profile["contents"]:
        content_profile = next(filter(lambda item: item["_source"]["url"] == item["content"], es.search(index=index_name, body={"query": {"match": {"url": item["content"]}}})["hits"]["hits"]), None)
        if not content_profile:
            continue
        for tag in content_profile["_source"]["tags"]:
            interests[tag] = interests.get(tag, 0) + item["count"]

    # 计算内容之间的相似度
    content_profiles = {}
    for item in es.search(index=index_name, body={"query": {"match_all": {}}}):
        content_profiles[item["_source"]["url"]] = [1 if tag in item["_source"]["tags"] else 0 for tag in interests.keys()]

    # 计算用户与内容之间的相似度
    similarities = {}
    for content, profile in content_profiles.items():
        similarities[content] = cosine_similarity(list(interests.values()), profile)

    # 按相似度从高到低排序
    recommendations = sorted(similarities.items(), key=lambda item: item[1], reverse=True)

    # 返回前N个推荐的内容
    return [item[0] for item in recommendations[:N]]

使用示例:

print(recommend("张三", 10))  # 输出:['www.pidancode.com', 'www.pidancode.com/java-tutorial', 'www.pidancode.com/elasticsearch-guide', 'www.pidancode.com/python-tutorial', 'www.pidancode.com/docker-deployment', 'www.pidancode.com', 'www.pidancode.com/java-tutorial', 'www.pidancode.com/elasticsearch-guide', 'www.pidancode.com/python-tutorial', 'www.pidancode.com/docker-deployment']

可以看到,推荐系统成功地根据用户画像和内容画像,对用户进行了推荐。

相关文章