目录
Graph Databases: Personalized Book Recommendations
一、图数据库建模优化(Cypher部分)
1. 扩展数据模型 - 添加更多关系和属性
// 1.1 添加图书主题和关键词节点
CREATE (t1:Topic {name:"数据库"}),
(t2:Topic {name:"文学"}),
(k1:Keyword {name:"图算法"}),
(k2:Keyword {name:"魔幻现实主义"})
// 1.2 建立图书-主题关系
MATCH (b:Book), (t:Topic)
WHERE b.book_id IN ["B001","B002"] AND t.name = "数据库"
CREATE (b)-[:HAS_TOPIC]->(t)
// 1.3 添加读者行为数据
MATCH (r:Reader {reader_id:"R001"})
SET r += {
reading_speed: 2.5, // 阅读速度(本/月)
preferred_time: "night" // 偏好晚间阅读
}
// 1.4 建立图书相似关系(基于共同借阅)
MATCH (b1:Book)<-[:BORROWED]-(:Reader)-[:BORROWED]->(b2:Book)
WHERE b1 <> b2
MERGE (b1)-[s:SIMILAR {weight: count(*)}]-(b2)
2. 用户画像查询
// 2.1 获取读者兴趣图谱
MATCH (r:Reader {reader_id:"R001"})-[:BORROWED]->(b:Book)-[:HAS_TOPIC]->(t:Topic)
RETURN r.name AS reader,
collect(DISTINCT t.name) AS interests,
avg(b.rating) AS avg_rating
// 2.2 发现读者社区(基于相似借阅模式)
MATCH (r1:Reader {reader_id:"R001"})-[:BORROWED]->()<-[:BORROWED]-(r2:Reader)
WITH r1, r2, count(*) AS overlap
WHERE overlap > 2
RETURN r2.name AS similar_reader,
overlap
ORDER BY overlap DESC
二、Python图分析与推荐实现
1. 图嵌入与特征提取
import networkx as nx
from node2vec import Node2Vec
from sklearn.cluster import KMeans
# 从Neo4j导入数据构建NetworkX图
def load_graph_from_neo4j():
G = nx.Graph()
# 添加节点和边(示例代码,实际需连接Neo4j)
G.add_node("R001", type='Reader', name='王小明')
G.add_node("B001", type='Book', title='Neo4j图数据库实战')
G.add_edge("R001", "B001", relation='BORROWED', weight=3)
return G
# 使用Node2Vec生成图嵌入
def generate_embeddings(G):
# 参数设置:p=1.0, q=0.5 控制随机游走策略
node2vec = Node2Vec(G, dimensions=64, walk_length=30,
num_walks=200, p=1, q=0.5, workers=4)
model = node2vec.fit(window=10, min_count=1)
return model
# 聚类分析读者兴趣
def cluster_readers(model, reader_ids):
vectors = [model.wv[rid] for rid in reader_ids]
kmeans = KMeans(n_clusters=5).fit(vectors)
return kmeans.labels_
2. 个性化推荐算法
import numpy as np
from scipy.spatial.distance import cosine
# 基于图嵌入的推荐
def graph_based_recommend(model, reader_id, top_n=5):
# 获取读者和图书的嵌入向量
reader_vec = model.wv[reader_id]
book_vecs = {n: model.wv[n] for n in model.wv.key_to_index
if n.startswith('B')}
# 计算余弦相似度
similarities = {
book: 1 - cosine(reader_vec, vec)
for book, vec in book_vecs.items()
}
# 返回TopN推荐
return sorted(similarities.items(),
key=lambda x: x[1], reverse=True)[:top_n]
# 混合推荐策略(结合协同过滤)
def hybrid_recommendation(reader_id):
# 从Neo4j获取协同过滤结果
cypher_query = """
MATCH (target:Reader {reader_id: $reader_id})-[:BORROWED]->()<-[:BORROWED]-(other:Reader)
WITH other, count(*) AS strength
ORDER BY strength DESC LIMIT 10
MATCH (other)-[:BORROWED]->(rec:Book)
WHERE NOT (target)-[:BORROWED]->(rec)
RETURN rec.book_id AS book, sum(strength) AS score
ORDER BY score DESC LIMIT 5
"""
cf_results = neo4j_session.run(cypher_query, reader_id=reader_id)
# 获取图嵌入推荐结果
graph_recs = graph_based_recommend(model, reader_id)
# 混合排序算法
combined = {}
for book, score in cf_results:
combined[book] = combined.get(book, 0) + score*0.7
for book, sim in graph_recs:
combined[book] = combined.get(book, 0) + sim*0.3
return sorted(combined.items(), key=lambda x: x[1], reverse=True)[:5]
三、完整工作流程实现:关键实现步骤
1. 数据增强(每日运行)
# 更新图书相似度关系
def update_book_similarity():
cypher = """
MATCH (b1:Book)<-[:BORROWED]-(r:Reader)-[:BORROWED]->(b2:Book)
WHERE b1 <> b2
MERGE (b1)-[s:SIMILAR]->(b2)
SET s.weight = COALESCE(s.weight,0) + 1
"""
neo4j_session.run(cypher)
2.实时推荐API
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/recommend/<reader_id>')
def get_recommendations(reader_id):
recommendations = hybrid_recommendation(reader_id)
return jsonify({
"reader_id": reader_id,
"recommendations": [
{"book_id": b, "score": float(s)}
for b,s in recommendations
]
})
3.读者画像可视化
def visualize_reader_profile(reader_id):
# 从Neo4j获取多维特征
query = """
MATCH (r:Reader {reader_id: $id})-[:BORROWED]->(b:Book)
OPTIONAL MATCH (b)-[:HAS_TOPIC]->(t:Topic)
RETURN {
basic_info: properties(r),
reading_history: collect(DISTINCT b.title),
interests: collect(DISTINCT t.name),
reading_metrics: {
total_books: count(DISTINCT b),
avg_borrow_duration: avg(duration.inDays(
date(br.borrow_date),
date(coalesce(br.return_date, date())))
)
}
} AS profile
"""
profile = neo4j_session.run(query, id=reader_id).single()["profile"]
# 使用Matplotlib生成雷达图
metrics = profile['reading_metrics']
labels = ['阅读量', '阅读深度', '阅读速度', '主题广度']
values = [
metrics['total_books'],
metrics['avg_borrow_duration'],
profile['basic_info']['reading_speed'],
len(set(profile['interests']))
]
# 绘制雷达图(代码略)
return radar_chart
四、应用场景实现
1. 动态资源优化
// 发现热门主题关联
MATCH (t1:Topic)<-[:HAS_TOPIC]-(:Book)<-[:BORROWED]-(:Reader)-[:BORROWED]->(:Book)-[:HAS_TOPIC]->(t2:Topic)
WHERE t1 <> t2
RETURN t1.name AS topic1,
t2.name AS topic2,
count(*) AS strength
ORDER BY strength DESC
LIMIT 10
2.个性化推送触发
# 检查新书是否符合读者兴趣
def check_new_book_match(book_id, reader_id):
reader_vec = model.wv[reader_id]
book_vec = model.wv[book_id]
similarity = 1 - cosine(reader_vec, book_vec)
return similarity > 0.7 # 阈值可调整
3.读者流失预警
# 基于图特征预测流失风险
def predict_churn_risk(reader_id):
query = """
MATCH (r:Reader {reader_id: $id})
OPTIONAL MATCH (r)-[br:BORROWED]->()
RETURN {
last_activity: duration.between(
date(br.borrow_date),
date()).days,
community_engagement: size((
MATCH (r)-[:BORROWED]->()<-[:BORROWED]-(:Reader)
RETURN 1
))
} AS features
"""
features = neo4j_session.run(query, id=reader_id).single()["features"]
# 使用预训练模型预测(示例逻辑)
risk_score = 0.3*features['last_activity'] - 0.7*features['community_engagement']
return max(0, min(1, risk_score))
五、性能优化
1 图数据库优化
1.1 为频繁查询路径创建索引
CREATE INDEX FOR (r:Reader) ON (r.reader_id)
CREATE INDEX FOR (b:Book) ON (b.book_id)
1.2 使用APOC库的图算法
CALL apoc.algo.pageRank(['Book','Reader'], 'BORROWED')
2 Python层优化
使用Dask并行处理大规模图计算;
缓存图嵌入模型(推荐使用Joblib);
增量更新策略减少全图计算。
3 推荐多样性保障
def diversify_recommendations(recommendations, top_n=5):
# 按主题聚类推荐结果
topics = get_book_topics([b for b,_ in recommendations])
clustered = {}
for (book, score), topic in zip(recommendations, topics):
clustered.setdefault(topic, []).append((book, score))
# 从每个主题选取代表
final = []
for topic in clustered:
final.append(max(clustered[topic], key=lambda x: x[1]))
return sorted(final, key=lambda x: x[1], reverse=True)[:top_n]
六、方案小结
深度图特征挖掘:利用图嵌入捕获高阶关系。
多策略融合:结合协同过滤与图算法。
实时动态更新:持续优化用户画像。
可解释性设计:通过可视化解释推荐逻辑。
七、附另一份完整代码
import matplotlib.pyplot as plt
import numpy as np
from neo4j import GraphDatabase
from datetime import datetime
import logging
class ReaderProfileVisualizer:
def __init__(self, neo4j_uri, username, password):
"""
初始化Neo4j数据库连接
"""
self.driver = GraphDatabase.driver(neo4j_uri, auth=(username, password))
self.setup_plot_style()
def setup_plot_style(self):
"""设置图表样式"""
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial'] # 支持中文显示
plt.rcParams['axes.unicode_minus'] = False
def get_reader_profile(self, reader_id):
"""
从Neo4j获取读者画像数据(优化后的查询)
"""
# 优化的Cypher查询
query = """
MATCH (r:Reader {reader_id: $reader_id})-[br:BORROWED]->(b:Book)
OPTIONAL MATCH (b)-[:HAS_TOPIC]->(t:Topic)
WITH r, br, b, t
WHERE br.borrow_date IS NOT NULL // 确保借阅日期存在
RETURN {
basic_info: properties(r),
reading_history: collect(DISTINCT b.title),
interests: collect(DISTINCT t.name),
reading_metrics: {
total_books: count(DISTINCT b),
avg_borrow_duration: avg(
duration.inDays(
date(br.borrow_date),
date(coalesce(br.return_date, date()))
).days
),
unique_topics: count(DISTINCT t.name),
completion_rate: toFloat(
count(CASE WHEN br.return_date IS NOT NULL THEN 1 ELSE NULL END)
) / count(br) * 100
}
} AS profile
"""
try:
with self.driver.session() as session:
result = session.run(query, reader_id=reader_id)
record = result.single()
if record is None:
raise ValueError(f"未找到读者ID: {reader_id}")
profile = record["profile"]
return self._validate_profile(profile)
except Exception as e:
logging.error(f"数据库查询错误: {e}")
raise
def _validate_profile(self, profile):
"""
验证和清理画像数据
"""
# 处理可能的空值
metrics = profile.get('reading_metrics', {})
basic_info = profile.get('basic_info', {})
# 设置默认值
metrics.setdefault('total_books', 0)
metrics.setdefault('avg_borrow_duration', 0)
metrics.setdefault('unique_topics', 0)
metrics.setdefault('completion_rate', 0)
basic_info.setdefault('reading_speed', 0)
# 确保interests是列表
profile['interests'] = profile.get('interests', []) or []
return profile
def normalize_metrics(self, values, max_values):
"""
标准化指标值到0-1范围,用于雷达图显示
"""
normalized = []
for i, value in enumerate(values):
if max_values[i] > 0:
normalized.append(min(value / max_values[i], 1.0))
else:
normalized.append(0)
return normalized
def create_radar_chart(self, profile, save_path=None):
"""
创建雷达图可视化
"""
metrics = profile['reading_metrics']
basic_info = profile['basic_info']
# 定义雷达图指标
categories = ['阅读量', '阅读深度', '阅读速度', '主题广度', '完成率']
# 原始值
raw_values = [
metrics['total_books'], # 阅读量
metrics['avg_borrow_duration'], # 平均借阅时长(阅读深度)
basic_info.get('reading_speed', 0), # 阅读速度
metrics['unique_topics'], # 主题广度
metrics['completion_rate'] / 100 # 完成率(转换为0-1)
]
# 设置各指标的最大值(可根据实际情况调整)
max_values = [50, 30, 100, 20, 1.0] # 示例最大值
# 标准化值
values = self.normalize_metrics(raw_values, max_values)
# 创建雷达图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, polar=True)
# 计算角度
angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False).tolist()
angles += angles[:1] # 闭合图形
values += values[:1]
# 绘制雷达图
ax.plot(angles, values, 'o-', linewidth=2, label='读者画像', color='#2E86AB')
ax.fill(angles, values, alpha=0.25, color='#2E86AB')
# 设置刻度标签
ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories, fontsize=12)
# 设置y轴刻度
ax.set_yticks([0.2, 0.4, 0.6, 0.8, 1.0])
ax.set_yticklabels(['20%', '40%', '60%', '80%', '100%'], fontsize=10)
ax.set_ylim(0, 1)
# 添加网格
ax.grid(True, alpha=0.3)
# 添加标题
reader_name = basic_info.get('name', f'读者{profile.get("basic_info", {}).get("reader_id", "未知")}')
plt.title(f'{reader_name} - 阅读画像雷达图', size=16, pad=20)
# 添加图例
plt.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
# 显示原始值标注
for i, (angle, value, raw_val) in enumerate(zip(angles[:-1], values[:-1], raw_values)):
if i < len(categories):
ax.annotate(f'{raw_val:.1f}',
xy=(angle, value),
xytext=(5, 5),
textcoords='offset points',
fontsize=9)
plt.tight_layout()
# 保存或显示图表
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"图表已保存至: {save_path}")
return fig, raw_values
def visualize_reader_profile(self, reader_id, save_path=None):
"""
主函数:完整的读者画像可视化流程
"""
try:
# 1. 获取读者画像数据
print(f"正在获取读者 {reader_id} 的画像数据...")
profile = self.get_reader_profile(reader_id)
# 2. 打印基本信息
self.print_profile_summary(profile)
# 3. 创建雷达图
print("正在生成雷达图...")
fig, values = self.create_radar_chart(profile, save_path)
# 4. 显示图表
plt.show()
return {
'profile': profile,
'figure': fig,
'metrics': values
}
except Exception as e:
logging.error(f"可视化过程中出错: {e}")
raise
def print_profile_summary(self, profile):
"""打印读者画像摘要"""
metrics = profile['reading_metrics']
basic_info = profile['basic_info']
print("\n" + "="*50)
print(f"读者画像摘要 - {basic_info.get('name', '未知读者')}")
print("="*50)
print(f"📚 总阅读量: {metrics['total_books']} 本书")
print(f"⏱️ 平均阅读时长: {metrics['avg_borrow_duration']:.1f} 天")
print(f"🚀 阅读速度: {basic_info.get('reading_speed', 0):.1f} 页/天")
print(f"🏷️ 兴趣主题: {metrics['unique_topics']} 个")
print(f"✅ 阅读完成率: {metrics['completion_rate']:.1f}%")
print(f"🎯 兴趣领域: {', '.join(profile['interests'][:5])}{'...' if len(profile['interests']) > 5 else ''}")
print("="*50 + "\n")
def close(self):
"""关闭数据库连接"""
self.driver.close()
# 使用示例
def main():
# 初始化可视化器
visualizer = ReaderProfileVisualizer(
neo4j_uri="bolt://localhost:7687",
username="neo4j",
password="password"
)
try:
# 可视化读者画像
reader_id = "R2024001"
result = visualizer.visualize_reader_profile(
reader_id=reader_id,
save_path=f"reader_{reader_id}_profile.png"
)
print("读者画像可视化完成!")
except Exception as e:
print(f"错误: {e}")
finally:
visualizer.close()
if __name__ == "__main__":
main()
七、欢迎纠错
欢迎纠错,随时更新。
联系方式:评论、私信,或 企鹅 :179 0042 182 。
码字不易,如觉得还可以,请给个免费的 zan 和 soucang ,让我有动力继续写下去。
八、免费爬虫
https://affiliate
.bazhuayu
.com
/M8lKUC
九、论文写作/Python 学习智能体
https://chatglm.cn/share/WF2C5ree
-
- 以下关于 Markdown 编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
++ 新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
++ 功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
++ 合理的创建标题,有助于目录的生成
直接输入1次+,并按下space后,将生成1级标题。
输入2次+,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。
++ 如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
++ 插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
++ 如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.
// An highlighted block
var foo = 'bar';
++ 生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
++ 创建一个表格
一个简单的表格是这么创建的:
| 项目 | Value |
|---|---|
| 电脑 | $1600 |
| 手机 | $12 |
| 导管 | $1 |
+++ 设定内容居中、居左、居右
使用:---------:居中
使用:----------居左
使用----------:居右
| 第一列 | 第二列 | 第三列 |
|---|---|---|
| 第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
+++ SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
| TYPE | ASCII | HTML |
|---|---|---|
| Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
| Quotes | "Isn't this fun?" | “Isn’t this fun?” |
| Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
++ 创建一个自定义列表
Markdown
: Text-to-HTML conversion tool
-
Authors
- John
- Luke
++ 如何创建一个注脚
一个具有注脚的文本。2
++ 注释也是必不可少的
Markdown将文本转换为 HTML。
++ KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
++ 新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
++ UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:
这将产生一个流程图。:
- 关于 Mermaid 语法,参考 这儿,
++ FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
++ 导出与导入
+++ 导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
+++ 导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎

被折叠的 条评论
为什么被折叠?



