{"success":true,"data":[{"id":"67f4cf91455186f56d9f412f","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h3>Neo4j 官方教程（持续更新中）</h3>\n<p>本教程引用Neo4j官方文档： <a href=\"https://neo4j.com/docs/\">https://neo4j.com/docs/</a>，内容持续更新中</p>\n<h3>目录</h3>\n<p><a href=\"http://neo4j.com.cn/topic/67f4c1f2c181bb8b583a8a67\">Neo4j官方教程：第1节，Neo4j是什么</a>\n<a href=\"http://neo4j.com.cn/topic/67f4c2c9c181bb8b583a8a68\">Neo4j官方教程：第2节，什么是图数据库</a>\n<a href=\"http://neo4j.com.cn/topic/67f4cbcf455186f56d9f412d\">Neo4j官方教程：第3节，图数据库概念</a>\n<a href=\"http://neo4j.com.cn/topic/67f4cf71455186f56d9f412e\">Neo4j官方教程：第4节，从关系型数据库过渡到图数据库</a>\n<a href=\"http://neo4j.com.cn/topic/67f4e38d455186f56d9f4130\">Neo4j官方教程：第5节，从NoSQL到图数据库的转型</a>\n<a href=\"http://neo4j.com.cn/topic/67f5cb22455186f56d9f4131\">Neo4j官方教程：第6节， 什么是 Cypher</a>\n<a href=\"http://neo4j.com.cn/topic/67f5ccf0455186f56d9f4132\">Neo4j官方教程：第7节， Cypher 与 SQL 比较</a>\n<a href=\"http://neo4j.com.cn/topic/67f5cf0f455186f56d9f4133\">Neo4j官方教程：第8节， 模式</a>\n<a href=\"http://neo4j.com.cn/topic/67f5d4a0455186f56d9f4134\">Neo4j官方教程：第9节，实践中的模式</a>\n<a href=\"http://neo4j.com.cn/topic/67f5db4e455186f56d9f4135\">Neo4j官方教程：第10节，获取正确的结果</a>\n<a href=\"http://neo4j.com.cn/topic/67f867115885e744204e1838\">Neo4j官方教程：第11节，更新数据</a>\n<a href=\"http://neo4j.com.cn/topic/67f869905885e744204e1839\">Neo4j官方教程：第12节，编写大型语句</a>\n<a href=\"http://neo4j.com.cn/topic/67fcc245a755994623e85dc4\">Neo4j官方教程：第13节， Cypher 中的子查询</a>\n<a href=\"http://neo4j.com.cn/topic/67fcc2eba755994623e85dc5\">Neo4j官方教程：第14节，定义模式</a>\n<a href=\"http://neo4j.com.cn/topic/67fcc47aa755994623e85dc6\">Neo4j官方教程：第15节，日期、日期时间和持续时间</a>\n<a href=\"http://neo4j.com.cn/topic/67fcc77da755994623e85dc7\">Neo4j官方教程：第16节， 如何扩展 Cypher</a>\n<a href=\"http://neo4j.com.cn/topic/6800a7d2a755994623e85dc8\">Neo4j官方教程：第17节， 导入数据</a>\n<a href=\"http://neo4j.com.cn/topic/6800a9ffa755994623e85dc9\">Neo4j官方教程：第18节， Cypher 资源</a>\n<a href=\"http://neo4j.com.cn/topic/680b51dfb13f67342db8ad61\">Neo4j官方教程：第19节， 图数据建模是什么</a>\n<a href=\"http://neo4j.com.cn/topic/680df39fb13f67342db8ad62\">Neo4j官方教程：第20节，创建图数据模型</a>\n<a href=\"http://neo4j.com.cn/topic/6826fa35b13f67342db8ad68\">Neo4j官方教程：第21节，重构图数据模型</a>\n<a href=\"http://neo4j.com.cn/topic/682700deb13f67342db8ad69\">Neo4j官方教程：第22节，数据建模设计</a>\n<a href=\"http://neo4j.com.cn/topic/686b8d6da8f5aea0094a7c64\">Neo4j官方教程：第23节，版本控制</a>\n<a href=\"http://neo4j.com.cn/topic/686b8eaaa8f5aea0094a7c65\">Neo4j官方教程：第24节，从关系型数据模型到图数据模型的建模</a>\n<a href=\"http://neo4j.com.cn/topic/686b8f2ea8f5aea0094a7c66\">Neo4j官方教程：第25节，图数据建模技巧</a></p>\n</div>","title":"《Neo4j 官方教程中文版》Neo4j首选学习资料（持续更新中）","last_reply_at":"2025-04-08T07:26:09.329Z","good":true,"top":true,"reply_count":0,"visit_count":9195,"create_at":"2025-04-08T07:26:09.329Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67ad4b328e65137814c5a995","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h2>官方下载页</h2>\n<p>下载地址：<a href=\"https://neo4j.com/deployment-center/\">https://neo4j.com/deployment-center/</a>\n打开后滚动到网页中部，如下位置选择版本下载\n<img src=\"http://neo4j.6laohu.com/Fvi7wYAyqeJ9ER9yy-lAScwjp6n0\" alt=\"image.png\"></p>\n<h2><s>Neo4j 2025.01.0 Released 6 February 2025</s></h2>\n<h3><s>Neo4j 社区版</s></h3>\n<h4><s>Windows 版压缩包</s></h4>\n<p><a href=\"https://dist.neo4j.org/neo4j-community-5.26.4-windows.zip\">neo4j-community-2025.01.0-windows.zip</a></p>\n<h4><s>Linux / Mac 版压缩包</s></h4>\n<p><a href=\"https://dist.neo4j.org/neo4j-community-5.26.4-unix.tar.gz\">neo4j-community-2025.01.0-unix.tar.gz</a></p>\n<h4><s>Debian / Ubuntu 版安装包</s></h4>\n<p><a href=\"https://dist.neo4j.org/deb/neo4j_5.26.4_all.deb\">neo4j_2025.01.0_all.deb</a></p>\n<h4><s>Red Hat Linux 版安装包</s></h4>\n<p><a href=\"https://dist.neo4j.org/rpm/neo4j-2025.03.0-1.noarch.rpm\">neo4j-2025.01.0-1.noarch.rpm</a></p>\n<h3><s>Neo4j桌面安装版 Neo4j Desktop 1.6.1</s></h3>\n<h4><s>Windows 版 Neo4j Desktop (exe)</s></h4>\n<p><a href=\"https://dist.neo4j.org/neo4j-desktop/win-offline/Neo4j%20Desktop%20Setup%201.6.1.exe\">Neo4j-Desktop-Setup-1.6.1.exe</a></p>\n<h4><s>Mac 版 Neo4j Desktop (dmg)</s></h4>\n<p><a href=\"https://dist.neo4j.org/neo4j-desktop/mac/Neo4j%20Desktop-1.6.1.dmg\">Neo4j-Desktop-1.6.1.dmg</a></p>\n</div>","title":"Neo4j 各个版本安装包下载点","last_reply_at":"2025-02-13T01:30:26.506Z","good":true,"top":true,"reply_count":0,"visit_count":22254,"create_at":"2025-02-13T01:30:26.506Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"64ad026377567df4044c1862","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p>NeuroDB是一个内存级图数据库引擎，能够利用Neuro-cypher指令实现对图数据的创建、编辑、检索 以及建立在复杂图算法上的一些高级图应用。官方主页：<a href=\"http://neurodb.org\">neurodb.org</a>\n视频介绍：【研发轻量级图数据库引擎：NeuroDB-哔哩哔哩】 <a href=\"https://b23.tv/DkFT60M\">https://b23.tv/DkFT60M</a></p>\n<p>NeuroDB的主要特性为：</p>\n<ul>\n<li>轻量级：整个引擎的可执行程序仅有不到400KB</li>\n<li>内存级：整个图数据被完全载入到内存中进行操作</li>\n<li>高速：得益于整个数据库都在内存中，无硬盘读写延迟</li>\n<li>可嵌入式：数据库可以嵌入到您项目里类似sqlite，无需单独部署运维</li>\n<li>跨平台：各主流操作系统（windows、Linux、Mac）以及手机操作系统（Android、IPhone）和任何可运行C语言目标程序的嵌入式系统或单片机（STM32）都可运行NeuroDB</li>\n<li>精简化：类似Redis，以精简的操控指令、精简的部署运维、精简的软件架构 实现强大、高效、低资源消耗的图数据库引擎</li>\n<li>全自主研发：提供图数据库国产替代方案</li>\n<li>提供边缘计算：得益于 NeuroDB的轻量级， 其可嵌入到 小型、微型设备上（芯片上） 实现“边缘计算”</li>\n<li>图建模概念：NeuroDB的可视化客户端实现了 类似 面向对象的 根据模型“派生”图数据的概念，可以在建模中设计 图的节点、关系关联机构，并且可以向关系数据库表结构那样 设计节点或关系上的属性（属性名、属性数据类型、属性数据长度等）</li>\n<li>NeuroDB 图数据库服务端 属于轻量级架构，整个服务端启动只占用系统 几KB的空间</li>\n</ul>\n<p><img src=\"http://neo4j.6laohu.com/FmPredJvxgRoW7ZhDZ9JENLEBQsc\" alt=\"image.png\">\nNeuroDB提供友好强大的图可视化界面：NeuroStudio，其实现了可视化数据展示、图数据编辑、图数据建模功能。</p>\n<p>特别的，NeuroStudio引入了“图建模”概念实现了 类似 面向对象的 根据模型“派生”图数据的概念，可以在建模中设计 图的节点、关系关联机构，并且可以向关系数据库表结构那样 设计节点或关系上的属性（属性名、属性数据类型、属性数据长度等）\n<img src=\"http://neo4j.6laohu.com/FqJx13yh4W5I4zucaDdmHwPCz9Lr\" alt=\"image.png\"></p>\n</div>","title":"NeuroDB图数据库引擎 发布，一款全自主研发的轻量级图数据库","last_reply_at":"2023-07-11T07:18:59.653Z","good":true,"top":true,"reply_count":0,"visit_count":5304,"create_at":"2023-07-11T07:18:59.653Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"59b7418c9fe13f5e0a2212c3","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p>本社区的技术交流QQ群为：\n1群：547190638 <a href=\"http://jq.qq.com/?_wv=1027&amp;k=40vEPbd\">点击加入QQ群</a></p>\n<p>2群：705837093 <a href=\"https://jq.qq.com/?_wv=1027&amp;k=5B7nj45\">点击加入QQ群</a></p>\n<p>3群：622711500 <a href=\"https://jq.qq.com/?_wv=1027&amp;k=1hMEVSVw\">点击加入QQ群</a></p>\n<p>加群请回答加群问题（用于防止不良人员加入）\nQQ群内如果没有人及时回答你的问题，请先发到本社区。</p>\n</div>","title":"Neo4j 中文社区 技术交流 QQ群，1群：547190638，2群：705837093，3群：511493693","last_reply_at":"2020-07-25T11:05:20.393Z","good":false,"top":true,"reply_count":3,"visit_count":14358,"create_at":"2017-09-12T02:08:12.245Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"6a29248fb46e89224e453e84","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h1>Conda 简明使用指南</h1>\n<h2>📦 核心概念</h2>\n<p>Conda = 环境管理器 + 包管理器，一个命令搞定 Python 版本、依赖包、甚至系统库（如 CUDA）。</p>\n<p>🚀 常用命令速查\n操作\t命令\n创建环境\tconda create -n 环境名 python=3.10\n激活环境\tconda activate 环境名\n退出环境\tconda deactivate\n安装包\tconda install 包名\n指定渠道安装\tconda install -c 渠道名 包名\n查看所有环境\tconda env list\n删除环境\tconda env remove -n 环境名\n导出环境\tconda env export &gt; environment.yml\n从文件创建环境\tconda env create -f environment.yml</p>\n<h2>🎯 针对你的项目：完整操作流程</h2>\n<pre class=\"prettyprint language-bash\"><code># 1. 创建项目专用环境（命名：securities_qa，Python 3.10）\nconda create -n securities_qa python=3.10\n\n# 2. 激活环境（命令行前出现 (securities_qa) 说明成功）\nconda activate securities_qa\n\n# 3. 安装 faiss-gpu（从 pytorch 渠道）\nconda install -c pytorch faiss-gpu\n\n# 4. 可选：安装 Jupyter（方便调试）\nconda install jupyter\n\n# 5. 退出环境（开发结束后）\nconda deactivate\n</code></pre><h2>🔄 常用工作流</h2>\n<p>日常开发流程：</p>\n<pre class=\"prettyprint language-bash\"><code># 每次打开新终端，先激活环境\nconda activate securities_qa\n\n# 然后正常写代码、运行脚本\npython main.py\n\n# 需要新包时，直接用 conda 或 pip（在 conda 环境里都可以）\nconda install pandas\n# 或\npip install langchain\n\n# 用完退出（可选，不退出也没影响）\nconda deactivate\n</code></pre><p>查看环境状态：</p>\n<pre class=\"prettyprint language-bash\"><code># 当前激活了哪个环境？\nconda info --envs\n\n# 当前环境装了哪些包？\nconda list\n</code></pre><p>删除重建环境（出问题时）：</p>\n<pre class=\"prettyprint language- bash\"><code>conda deactivate\nconda env remove -n securities_qa\nconda create -n securities_qa python=3.10\n</code></pre><h2>💡 关键技巧</h2>\n<p>激活环境后，pip/uv 装的包也在 conda 环境里，不冲突</p>\n<p>conda install 很慢：可换国内源（清华/中科大）加速</p>\n<p>不确定包名：conda search 关键词 查找</p>\n<p>环境移植：conda env export &gt; environment.yml 分享给队友</p>\n<h2>📋 你的项目下一步</h2>\n<pre class=\"prettyprint language- bash\"><code>conda activate securities_qa\nconda install -c pytorch faiss-gpu\nuv pip install langchain langchain-community ollama chromadb\n</code></pre><p>然后就可以开始写代码了！</p>\n</div>","title":"Conda 简明使用指南","last_reply_at":"2026-06-10T08:47:11.247Z","good":false,"top":false,"reply_count":0,"visit_count":200,"create_at":"2026-06-10T08:47:11.247Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"6a0d3bb270557b690faa5bb5","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h3>介绍</h3>\n<p>图数据库厂商Neo4j公司今日发布了Infinigraph，称其为分布式图技术的重大进步。</p>\n<p>该公司表示，这一架构允许用户在单一图数据库平台上同时运行操作和分析工作负载，处理规模超过100TB，且无需分割图结构、复制基础设施或影响性能。</p>\n<p>经过两年多的开发，Infinigraph解决了事务系统与分析工作负载协调的问题。Neo4j的早期版本需要在单台物理计算机上运行，这意味着组织必须使用提取/传输/加载管道、同步或多个数据库来处理大量数据。</p>\n<p>Infinigraph通过使用分片技术解决了这一限制。分片是一种将大型数据集拆分为更小、更易管理片段的数据库技术，可支持数十亿关系和数千个并发查询跨多个处理器执行，同时保持事务场景所需的原子性、一致性、隔离性和持久性（ACID）特性。</p>\n<p>该公司可以在多台机器间对图数据进行分片，同时保持其逻辑一致性，实现数据的自动分发和扩展，无需应用程序重写或人工干预。</p>\n<p>Neo4j表示，新架构允许客户将数千万文档作为向量直接嵌入图中。这使得欺诈检测、产品知识图谱、长期合规监控和语义搜索等用例能够在更大、更丰富的数据量上进行。</p>\n<p>Neo4j技术总裁Sudhir Hasbe表示：“我们现在能够在Neo4j数据库中支持数十亿个向量。这在生命科学领域特别有用，公司需要处理数千万份科学文档进行药物发现。过去，这些文档是孤立的。现在，它们可以直接嵌入到图中。”</p>\n<p>四年前，Neo4j通过引入Fabric为新架构奠定了基础，实现了跨机器的联邦图查询，但客户必须自己管理分片。Infinigraph自动化了这一过程，同时保持完整的ACID合规性。</p>\n<p>&quot;由于遍历查询的存在，图分片是一个困难的问题，&quot;Hasbe说，“我们通过在一个环境中维护全局索引实现快速路径查询，同时将实际数据分布在多台机器上实现水平扩展来解决这个问题。即使是分布式事务也保持一致和可靠。”</p>\n<p>Neo4j还强调了图作为生成式AI中使用的向量数据库的价值。AI训练需要结构化和非结构化数据。该公司在2023年首次添加了向量支持，允许文档以向量嵌入的形式存储。Infinigraph实现了更大规模的存储。</p>\n<p>&quot;生成式AI使非结构化数据比以往更有价值，&quot;Hasbe说，“我们看到客户从使用Elastic Store处理向量转向在Neo4j内管理一切。这大大简化了他们的技术栈。”</p>\n<p>Infinigraph目前在Neo4j自管理企业版中提供早期访问，更广泛的可用性计划在10月推出。该公司表示，该功能很快将在其AuraDB云原生图平台中提供。</p>\n<p>Infinigraph的定价将采用解耦模式，分离计算和存储以提供更大的灵活性。&quot;我们正在将定价模式与现代分布式系统的运行方式保持一致，&quot;Hasbe说，&quot;这允许客户扩展工作负载而不会产生意外成本。&quot;他表示，工作负载较小的客户可能会看到成本较当前支付的费用有所下降。</p>\n<h3>Q&amp;A</h3>\n<p>Q1：Infinigraph是什么？它解决了什么问题？</p>\n<p>A：Infinigraph是Neo4j公司发布的分布式图技术架构，它解决了事务系统与分析工作负载协调的问题。该架构允许用户在单一图数据库平台上同时运行操作和分析工作负载，处理规模超过100TB，无需分割图结构、复制基础设施或影响性能。</p>\n<p>Q2：Infinigraph与之前的Neo4j版本有什么区别？</p>\n<p>A：之前的Neo4j版本需要在单台物理计算机上运行，组织必须使用多个数据库来处理大量数据。Infinigraph通过分片技术可以在多台机器间对图数据进行分片，同时保持逻辑一致性，实现数据的自动分发和扩展，无需应用程序重写或人工干预。</p>\n<p>Q3：Infinigraph在生成式AI方面有什么优势？</p>\n<p>A：Infinigraph能够支持数十亿个向量，可以将数千万文档作为向量直接嵌入图中。这在生命科学等领域特别有用，比如处理数千万份科学文档进行药物发现。生成式AI使非结构化数据更有价值，客户可以在Neo4j内管理一切，大大简化技术栈。</p>\n</div>","title":"Neo4j发布Infinigraph架构，统一实时交易与图分析处理","last_reply_at":"2026-05-20T04:42:26.230Z","good":false,"top":false,"reply_count":0,"visit_count":408,"create_at":"2026-05-20T04:42:26.230Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"69fdcc1d70557b690faa5bb3","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h1>图数据库到底是什么？一篇讲清楚核心原理、应用场景和选型指南</h1>\n<p><img src=\"http://neo4j.6laohu.com/FpiVH0Gs_Dx9-7HM2p9RIAZDkrxz\" alt=\"微信图片_20260508194705_162_5.jpg\"></p>\n<blockquote>\n<p>当关系型数据库还在「连表查询」时，图数据库已经在走「朋友的朋友的朋友」了</p>\n</blockquote>\n<p>每天都在聊知识图谱、GraphRAG，图数据库这个词你一定不陌生。但你真的搞懂了它是什么、怎么工作、什么时候该用吗？</p>\n<p>这篇文章不堆砌术语，从原理到选型，给你一次性讲透。</p>\n<hr>\n<h2>一、一句话说清楚图数据库</h2>\n<p><strong>图数据库 = 专门用来存储和处理「关系」的数据库。</strong></p>\n<p>它不是存图的（别被名字骗了）。它存的是<strong>实体（节点）<strong>和</strong>实体之间的关系（边）</strong>，每一个关系都是「一等公民」。</p>\n<p>举个例子，在传统数据库里你要查「张三的朋友的朋友是谁」，需要写三四个 JOIN 才能搞定；在图数据库里，你只要说「沿着朋友关系走两步」，它就知道你要什么。</p>\n<hr>\n<h2>二、核心模型：属性图</h2>\n<p>图数据库基于图论，最主流的数据模型叫<strong>属性图（Property Graph）</strong>，只有三个概念：</p>\n<p>1️⃣ <strong>节点</strong>：代表实体。可以是人、公司、文章、商品……任何东西。</p>\n<p>2️⃣ <strong>边</strong>：代表实体之间的关系。每条边都有<strong>方向</strong>（A→B）、<strong>类型</strong>（朋友/属于/购买）和<strong>属性</strong>。比如：</p>\n<blockquote>\n<p>（小明）—[任职于 {职务：CEO}]→（字节跳动）</p>\n</blockquote>\n<p>3️⃣ <strong>属性</strong>：节点和边都可以挂上键值对，存额外信息。</p>\n<p><strong>和关系型数据库的最大区别</strong>：在 MySQL 里，「关系」是通过外键和 JOIN 连接出来的，查询时实时计算；在图数据库里，「关系」本身就是数据，存的时候就贴身挨着。</p>\n<hr>\n<h2>三、高性能的秘密：无索引邻接</h2>\n<p>图数据库快的根本原因，是一个词：<strong>无索引邻接（Index-Free Adjacency）</strong>。</p>\n<p>什么意思？在图数据库里，每个节点都直接存着它所有邻居的「指针」——就像你手机通讯录里直接存了朋友的电话号码，不需要翻黄页查。</p>\n<p>当你查「A 的朋友的朋友的朋友」：</p>\n<ul>\n<li>图数据库：A→邻居1（沿指针）→邻居2（沿指针）→邻居3 → 找到</li>\n<li>关系型数据库：查表→建索引→JOIN→JOIN→JOIN → 找到，但速度差几个数量级</li>\n</ul>\n<p>深度为 3 到 5 层的多跳查询，图数据库比 MySQL 快 <strong>几十倍甚至几百倍</strong>。</p>\n<hr>\n<h2>四、图数据库分类一次看懂</h2>\n<p>别看都叫「图数据库」，内部差异很大。按存储架构分：</p>\n<p><strong>原生图数据库</strong></p>\n<ul>\n<li>存储引擎从一开始就为图结构优化</li>\n<li>性能和遍历速度最快</li>\n<li>代表：Neo4j、NebulaGraph、TigerGraph</li>\n</ul>\n<p><strong>多模型数据库</strong></p>\n<ul>\n<li>一个系统支持图 + 文档 + KV 多种模型</li>\n<li>灵活方便，但纯图查询性能稍弱</li>\n<li>代表：ArangoDB、OrientDB</li>\n</ul>\n<p><strong>分布式图数据库</strong></p>\n<ul>\n<li>为百亿级数据设计，可以水平扩展</li>\n<li>适合海量实时场景，但事务支持较弱</li>\n<li>代表：NebulaGraph、JanusGraph、TigerGraph</li>\n</ul>\n<p><strong>单机/嵌入式</strong></p>\n<ul>\n<li>轻量，适合小项目</li>\n<li>代表：Neo4j 社区版、SQLite 图扩展</li>\n</ul>\n<hr>\n<h2>五、主流查询语言横向对比</h2>\n<table>\n<thead>\n<tr>\n<th>语言家族</th>\n<th>代表产品</th>\n<th>特点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Cypher</td>\n<td>Neo4j、NebulaGraph</td>\n<td>声明式，像 SQL，学习曲线平缓</td>\n</tr>\n<tr>\n<td>Gremlin</td>\n<td>JanusGraph、Neptune</td>\n<td>命令式，灵活但复杂</td>\n</tr>\n<tr>\n<td>GSQL / nGQL</td>\n<td>TigerGraph、NebulaGraph</td>\n<td>接近 SQL，对传统DBA友善</td>\n</tr>\n<tr>\n<td>SPARQL</td>\n<td>Stardog、GraphDB</td>\n<td>语义网标准，适合知识图谱推理</td>\n</tr>\n</tbody>\n</table>\n<p>如果你是新手，<strong>从 Cypher 入手最友好</strong>。它的查询长什么样？比如「找张三朋友推荐的书」：</p>\n<pre class=\"prettyprint\"><code>MATCH (张三:Person)-[:朋友]-&gt;(朋友:Person)-[:推荐]-&gt;(书:Book)\nRETURN 书.title\n</code></pre><p>是不是还挺直观的？</p>\n<hr>\n<h2>六、图数据库在解决什么问题？</h2>\n<p><strong>社交网络</strong>\n推荐可能认识的人、发现社群结构。关系天然就是图，为什么非要把图装进方形的表里？</p>\n<p><strong>知识图谱</strong>\n「某公司的CTO之前在哪家公司工作过？」——知识图谱就是属性图，图数据库是最佳底座。</p>\n<p><strong>反欺诈与风控</strong>\n欺诈团伙往往是隐蔽的关系网络。图数据库能三跳之内揪出关联账户和交易环。</p>\n<p><strong>推荐系统</strong>\n「你朋友喜欢的东西，你可能也喜欢」——这句话本身就是图的遍历。</p>\n<p><strong>供应链与物流</strong>\n追踪原材料来源、发现供应链瓶颈。上下游关系天然是图。</p>\n<p><strong>IT运维</strong>\n服务调用链、故障根因定位。微服务越拆越细，关系越来越复杂，图数据库看得很清楚。</p>\n<hr>\n<h2>七、主流产品怎么选？</h2>\n<p><strong>Neo4j</strong></p>\n<ul>\n<li>查多跳关系最强，生态最成熟</li>\n<li>适合中小规模、复杂关系分析</li>\n<li>事务支持强（ACID）</li>\n<li>分布式能力近年才补齐</li>\n</ul>\n<p><strong>NebulaGraph</strong></p>\n<ul>\n<li>分布式原生，千亿边不在话下</li>\n<li>计算存储分离，国产开源</li>\n<li>适合海量实时查询（社交、风控）</li>\n<li>事务较弱（单行事务）</li>\n</ul>\n<p><strong>TigerGraph</strong></p>\n<ul>\n<li>分布式，混合存储</li>\n<li>支持深度链路分析，内置大量图算法</li>\n<li>查询语言 GSQL 像 SQL，对传统开发者友好</li>\n</ul>\n<p><strong>JanusGraph</strong></p>\n<ul>\n<li>开源，后端可接 HBase/Cassandra</li>\n<li>适合已有大数据基础设施的团队</li>\n<li>无原生存储，性能受后端影响</li>\n</ul>\n<p><strong>ArangoDB</strong></p>\n<ul>\n<li>多模型：图 + 文档 + KV 一库搞定</li>\n<li>适合场景复杂但不想维护多套数据库的团队</li>\n</ul>\n<hr>\n<h2>八、总结：什么时候该上图数据库？</h2>\n<p>✅ <strong>适合用图数据库的场景</strong>：</p>\n<ul>\n<li>业务的核心是「关系」和「连接」</li>\n<li>查询涉及两层以上的关联跳转（朋友的朋友、资金流向图等）</li>\n<li>关系类型多、频繁变化</li>\n<li>需要做图算法分析（最短路径、社区发现、PageRank）</li>\n</ul>\n<p>❌ <strong>别用图数据库的场景</strong>：</p>\n<ul>\n<li>只做简单的单点查询（按ID查用户信息）→ 用 KV 或 MySQL</li>\n<li>数据之间没有天然关联 → 用文档数据库</li>\n<li>需要复杂的聚合统计和报表 → 用 OLAP 引擎</li>\n</ul>\n<p>一句话总结：</p>\n<blockquote>\n<p><strong>如果业务核心是「实体本身」</strong> → 用关系型数据库</p>\n<p><strong>如果业务核心是「实体之间的关系」</strong> → 上图数据库</p>\n</blockquote>\n<hr>\n<p><em>觉得有用？点个「在看」，转发给你的技术团队同事，一起搞清楚图数据库到底值不值得用。</em></p>\n<p><em>关注本公众号，下一期聊：GraphRAG——图数据库+大模型，能否彻底干掉传统 RAG？</em></p>\n<hr>\n<p>📝 <em>本文参考自腾讯云开发者社区技术文章及多个图数据库产品官方文档整理</em></p>\n</div>","title":"图数据库小白经常问的问题","last_reply_at":"2026-05-08T11:42:21.563Z","good":false,"top":false,"reply_count":0,"visit_count":620,"create_at":"2026-05-08T11:42:21.563Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"69606769243e73b30c0db24b","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p>参考官方：<a href=\"https://neo4j.com/docs/operations-manual/5/database-internals/store-formats/\">https://neo4j.com/docs/operations-manual/5/database-internals/store-formats/</a></p>\n<h2>Neo4j 存储格式概述</h2>\n<p>Neo4j 使用不同的存储格式（store formats）来将图数据持久化到磁盘上，每种格式针对特定的性能、容量和可扩展性需求进行了优化。截至 Neo4j 5.x 版本（2026 年 1 月，5.23 版本已发布），支持的格式包括 block、aligned、standard 和 high_limit。其中，block 格式是 Neo4j 5.22 及以后版本中 Enterprise Edition 新建数据库的推荐默认格式，具有最佳性能（基于块存储和数据内联）。aligned 格式是 Community Edition 和早期 Enterprise Edition 的默认格式。standard 和 high_limit 格式自 Neo4j 5.23 起已被弃用，不推荐用于新数据库，支持将于 2029 年 11 月结束。</p>\n<p>这些格式的主要区别在于数据结构、实体容量上限、ID 分配方式、性能表现、磁盘占用以及迁移路径。以下详细说明每种格式，所有信息请以 Neo4j 官方文档（Operations Manual 5 版）的 <a href=\"https://neo4j.com/docs/operations-manual/5/database-internals/store-formats/\">Store formats 章节</a> 及其子页面内容为准。</p>\n<h2>1. Block 格式</h2>\n<ul>\n<li>格式版本：block-block-1.1</li>\n<li>引入版本：Neo4j 5.14（5.16 正式 GA）</li>\n<li>默认使用场景：Neo4j 5.22 及以后 Enterprise Edition 新建数据库（除非通过 db.format 配置覆盖）</li>\n<li>可用版本：仅 Enterprise Edition</li>\n<li>数据结构：基于块（block）的存储，采用内联（inlining）技术。属性与节点、关系共置于块中，提升数据局部性，减少指针跳转。与基于记录（record）的格式（链表式结构）形成对比。</li>\n<li>实体容量限制：\n<ul>\n<li>节点：最高 2⁴⁸（约 281 万亿）</li>\n<li>关系：无限制</li>\n<li>属性：无限制</li>\n<li>标签：最高 2³¹（约 21 亿）</li>\n<li>关系类型：最高 2³⁰（约 10 亿）</li>\n<li>属性键：最高 2³¹（约 21 亿）</li>\n</ul>\n</li>\n<li>ID 分配：内部 ID 表示数据在存储文件中的物理位置。迁移到或从该格式时 ID 会被重新分配，可能导致外部引用 ID 的应用失效。</li>\n<li>性能表现：所有格式中最高，缓存效率高、页面故障少、I/O 操作少，适合高性能和大尺度图查询。</li>\n<li>磁盘占用：高效，开销最小。</li>\n<li>推荐使用场景：所有新 Enterprise Edition 数据库，尤其是需要高性能、可扩展性和内存效率的生产环境。</li>\n<li>迁移：可从 aligned、standard（以及有限情况下 high_limit）迁移而来。使用 neo4j-admin database migrate --to-format=“block” 离线执行，需要约 1 倍数据库大小的空闲磁盘空间，迁移后需重新填充索引。</li>\n</ul>\n<h2>2. Aligned 格式</h2>\n<ul>\n<li>格式版本：record-aligned-1.1</li>\n<li>引入版本：Neo4j 5.0</li>\n<li>默认使用场景：Community Edition 数据库及 Neo4j 5.22 之前创建的 Enterprise Edition 数据库</li>\n<li>可用版本：Community 和 Enterprise Edition</li>\n<li>数据结构：基于记录，增加了对齐（alignment）优化，提升内存效率。数据以链表式结构存储，但记录带有填充以对齐边界。</li>\n<li>实体容量限制：\n<ul>\n<li>节点：最高 2³⁵（约 343 亿）</li>\n<li>关系：最高 2³⁵（约 343 亿）</li>\n<li>属性：最高 2³⁶（约 687 亿）</li>\n<li>标签：最高 2³¹（约 21 亿）</li>\n<li>关系类型：最高 2¹⁶（65,536）</li>\n<li>属性键：最高 2²⁴（约 1678 万）</li>\n<li>关系组：最高 2³⁵（约 343 亿）</li>\n</ul>\n</li>\n<li>ID 分配：ID 对应存储文件中的物理偏移。迁移时重新分配。</li>\n<li>性能表现：优于 standard，但由于链表指针跳转，仍逊于 block。</li>\n<li>磁盘占用：因对齐填充略高于 standard。</li>\n<li>推荐使用场景：Community Edition 或旧 Enterprise 数据库，适用于容量在限制内的中等负载。</li>\n<li>迁移：可迁移至 block（推荐）或 high_limit（不推荐）。过程离线且 I/O 密集。</li>\n</ul>\n<h2>3. Standard 格式</h2>\n<ul>\n<li>格式版本：record-standard-1.1</li>\n<li>引入版本：Neo4j 5.0（从早期版本演进）</li>\n<li>默认使用场景：旧版本数据库，非当前默认</li>\n<li>可用版本：Community 和 Enterprise Edition</li>\n<li>弃用状态：自 Neo4j 5.23 起弃用，将在下一个 LTS 版本（预计 2026 年 11 月）后移除支持</li>\n<li>数据结构：基础记录存储，无对齐优化，纯链表式结构。</li>\n<li>实体容量限制：与 aligned 相同（节点/关系 2³⁵，属性 2³⁶ 等）</li>\n<li>ID 分配：物理位置 ID，迁移时重新分配。</li>\n<li>性能表现：基础水平，指针跳转导致较高延迟。</li>\n<li>磁盘占用：记录格式中最低。</li>\n<li>推荐使用场景：仅用于遗留兼容，不建议新建。应迁移至 block 或 aligned。</li>\n<li>迁移：可迁移至 aligned、block 或 high_limit（后者不推荐）。</li>\n</ul>\n<h2>4. High-Limit 格式</h2>\n<ul>\n<li>格式版本：record-high_limit-1.1</li>\n<li>引入版本：Neo4j 5.0（从早期版本演进）</li>\n<li>默认使用场景：从不默认，必须显式指定</li>\n<li>可用版本：仅 Enterprise Edition</li>\n<li>弃用状态：自 Neo4j 5.23 起弃用，同 standard</li>\n<li>数据结构：记录格式，针对极端容量设计，使用更宽的 ID 和额外开销。</li>\n<li>实体容量限制：\n<ul>\n<li>节点：最高 2⁵⁰（约 1 万亿亿，即 1 quadrillion）</li>\n<li>关系：最高 2⁵⁰</li>\n<li>属性：最高 2⁵⁰</li>\n<li>标签：最高 2³¹（约 21 亿）</li>\n<li>关系类型：最高 2²⁴（约 1678 万）</li>\n<li>属性键：最高 2²⁴（约 1678 万）</li>\n<li>关系组：最高 2⁵⁰</li>\n</ul>\n</li>\n<li>ID 分配：更宽位分配的物理位置 ID，迁移时重新分配。</li>\n<li>性能表现：因容量开销略差于 standard。</li>\n<li>磁盘占用：所有格式中最高。</li>\n<li>推荐使用场景：仅用于超出其他格式容量的极端大图；已弃用，应迁移至 block（注意 block 容量虽高但非无限）。</li>\n<li>迁移：仅可迁移至 block（迁移前会检查是否符合 block 容量限制）。</li>\n</ul>\n<h2>格式对比总结表</h2>\n<table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n<th></th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>特性</td>\n<td>Block 格式</td>\n<td>Aligned 格式</td>\n<td>Standard 格式</td>\n<td>High-Limit 格式</td>\n</tr>\n<tr>\n<td>数据结构</td>\n<td>块存储 + 内联</td>\n<td>记录 + 对齐</td>\n<td>基础记录</td>\n<td>记录 + 高容量设计</td>\n</tr>\n<tr>\n<td>最大节点数</td>\n<td>2⁴⁸（281 万亿）</td>\n<td>2³⁵（343 亿）</td>\n<td>2³⁵（343 亿）</td>\n<td>2⁵⁰（1 万亿亿）</td>\n</tr>\n<tr>\n<td>最大关系数</td>\n<td>无限制</td>\n<td>2³⁵（343 亿）</td>\n<td>2³⁵（343 亿）</td>\n<td>2⁵⁰（1 万亿亿）</td>\n</tr>\n<tr>\n<td>最大属性数</td>\n<td>无限制</td>\n<td>2³⁶（687 亿）</td>\n<td>2³⁶（687 亿）</td>\n<td>2⁵⁰（1 万亿亿）</td>\n</tr>\n<tr>\n<td>关系类型数</td>\n<td>2³⁰（10 亿）</td>\n<td>2¹⁶（65,536）</td>\n<td>2¹⁶（65,536）</td>\n<td>2²⁴（1678 万）</td>\n</tr>\n<tr>\n<td>属性键数</td>\n<td>2³¹（21 亿）</td>\n<td>2²⁴（1678 万）</td>\n<td>2²⁴（1678 万）</td>\n<td>2²⁴（1678 万）</td>\n</tr>\n<tr>\n<td>性能</td>\n<td>最佳（低 I/O、高缓存效率）</td>\n<td>良好</td>\n<td>基础</td>\n<td>略差于 standard</td>\n</tr>\n<tr>\n<td>磁盘占用</td>\n<td>高效</td>\n<td>中等（对齐开销）</td>\n<td>最低</td>\n<td>最高（容量开销）</td>\n</tr>\n<tr>\n<td>状态</td>\n<td>活跃，Enterprise 推荐</td>\n<td>活跃，Community 默认</td>\n<td>已弃用（5.23）</td>\n<td>已弃用（5.23）</td>\n</tr>\n<tr>\n<td>可用版本</td>\n<td>仅 Enterprise</td>\n<td>Community &amp; Enterprise</td>\n<td>Community &amp; Enterprise</td>\n<td>仅 Enterprise</td>\n</tr>\n<tr>\n<td>ID 分配</td>\n<td>物理位置，迁移重分配</td>\n<td>物理位置，迁移重分配</td>\n<td>物理位置，迁移重分配</td>\n<td>物理位置，迁移重分配</td>\n</tr>\n<tr>\n<td>可迁移目标</td>\n<td>N/A（目标格式）</td>\n<td>到 block 或 high_limit</td>\n<td>到 aligned、block 或 high_limit</td>\n<td>仅到 block</td>\n</tr>\n</tbody>\n</table>\n<h2>附加说明</h2>\n<ul>\n<li>查看当前格式：使用 Cypher SHOW DATABASES YIELD name, store 或命令行 neo4j-admin database info &lt;database&gt;。</li>\n<li>设置格式：新建数据库时通过 neo4j.conf 中的 db.format 配置，或在创建/导入时指定。</li>\n<li>弃用影响：standard 和 high_limit 将于 2029 年 11 月后失去支持，Enterprise 用户强烈建议迁移至 block以获得性能提升。</li>\n</ul>\n</div>","title":"Neo4j 不同的存储格式（store formats）的差异","last_reply_at":"2026-01-09T02:26:49.382Z","good":false,"top":false,"reply_count":0,"visit_count":1987,"create_at":"2026-01-09T02:26:49.382Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"68f63beca8f5aea0094a7c78","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p>图表分析在企业决策中能够发挥极大的价值，而好的图形算法不仅易于使用，执行速度快，而且能够产生强大的结果。Neo4j包含一个不断增长的开放式高性能图形算法库，可以揭示连接数据中的隐藏模式和结构。\n本文将为大家介绍Neo4j中提供的诸多图算法以及它们的功能。使用Neo4j图形算法，用户可以建模并预测复杂的动态特性，例如资源或信息的流动，传染或网络故障传播的途径，以及组的影响和弹性。\n由于Neo4j是将原生图平台中的分析和事务操作结合在一起，用户不仅可以揭示真实世界系统的内在本质，还可以更快地开发和部署基于图形的解决方案，并具有易于使用、简化的工作流程。</p>\n<h2>遍历和寻路算法</h2>\n<h3>1.广度优先算法(BFS)</h3>\n<p>做什么：遍历树数据结构，探索最近的邻居和他们的次级邻居。它用于定位连接，是许多其他图算法的前身。\n当树较不平衡或目标更接近起点时，BFS是首选。它也可用于查找节点之间的最短路径或避免深度优先搜索的递归过程。\n如何使用：广度优先搜索可用于定位像BitTorrent等对等网络中的邻居节点，GPS系统可精确定位附近的位置，社交网络服务可在特定距离内查找人员。</p>\n<h3>2.深度优先算法(DFS)</h3>\n<p>做什么：遍历树数据结构，通过在回溯之前尽可能探索每个分支。用于深层次的数据，是许多其他图算法的前身。当树较平衡或目标更接近端点时，深度优先搜索是首选。\n如何使用：深度优先算法通常用于游戏模拟，其中每个选择或动作引发另一个操作，从而扩展成可能性的树形图。它将遍历选择树，直到找到最佳解决方案路径(即胜利)。</p>\n<h3>3.单源最短路径</h3>\n<p>做什么：计算节点与所有其他节点之间的路径，以及其与所有其他节点的总和值(成本，距离，时间或容量等关系的权重)并得出总和最小。\n如何使用：单源最短路径通常用于自动获取物理位置之间的路线，例如通过Google地图获取驾车路线。在逻辑路由中也很重要，例如电话呼叫路由(最低成本路由)。</p>\n<h3>4.全源最短路径</h3>\n<p>做什么：计算包含图中节点之间所有最短路径的最短路径森林(组)。当最短路径被阻塞或变得次优时，切换到新的最短路径，通常用于备用路由。\n如何使用：用于评估备用路由，例如高速公路备份或网络容量。它也是为逻辑路由提供多路径的关键，比如呼叫路由选择。</p>\n<h3>5.最小生成树(MWST)</h3>\n<p>做什么：计算与访问树中所有节点相关的最小值(如成本，时间或容量等关系的权重)的路径，用于逼近一些NP难题，如旅行商问题和随机或迭代舍入。\n如何使用：最小生成树广泛用于网络设计：成本最低的逻辑或物理路由，如铺设电缆，最快的垃圾收集路线，供水系统容量，高效电路设计等等。它还可用于滚动优化的实时应用程序，如化学炼油厂的过程或行驶路线修正。\nCentrality Algorithms</p>\n<h3>6. PageRank</h3>\n<p>做什么：估计当前节点对其相邻节点的重要性，然后再从其邻居那里获得节点的重要性。一个节点的排名来源于其传递链接的数量和质量。PageRank虽然被谷歌抛弃了，但它还是被广泛认为是检测任何网络中有影响力的节点的常用方式。\n如何使用：PageRank用于评估重要性和影响力，经常的用法是推荐推特账户以及一般的情绪分析。\nPageRank也用于机器学习，以确定最有影响的提取特征。在生物学中，它被用来识别食物网中哪些物种的灭绝会导致物种死亡的最大连锁反应。</p>\n<h3>7. Degree Centrality</h3>\n<p>做什么：测量节点(或整个图表)所具有的关系数量，被分为流入和流出两个方向，关系具有指向性。\n如何使用：Degree Centrality着眼于用途的直接连通性，例如评估患者接近病毒或听取信息的近期风险。在社会研究中，可以用来预估人气或者其它情感。</p>\n<h3>8. Closeness Centrality</h3>\n<p>做什么：衡量一个节点对其集群内所有邻居的集中程度。假定到所有其他节点的路径都是最短的，那么该节点就能够以最快的速度到达整个组。\n如何使用：Closeness Centrality适用于多种资源、交流和行为分析，尤其是当交互速度显着时。\n在新公共服务中，被用于确定最大可访问性的位置。\n在社交网络分析中，用于找到具有理想社交网络位置的人，以便更快地传播信息。</p>\n<h3>9. Betweenness Centrality</h3>\n<p>做什么：测量通过节点的最短路径的数量(首先通过广度优先算法找到)。出现在最短路径上次数最多的节点具有较高的介数中心性，并且是不同集群之间的桥梁。它通常与控制资源和信息的流动有关。\n如何使用：Betweenness Centrality适用于网络科学中的各种问题，用于查明通信和交通网络中的瓶颈或可能的攻击目标。在基因组学中，被用于了解控制某些基因在蛋白质网络中的改进，例如更好的药物/疾病靶向。\nBetweenness Centrality也被用来评估多人在线游戏玩家和共享医师专业知识的信息流。</p>\n<h2>社区发现算法</h2>\n<p>这个类别也被称为聚类算法或分区算法。</p>\n<h3>10. Label Propagation</h3>\n<p>做什么：基于邻域多数的标签作为推断集群的手段。这种极其快速的图形分割需要很少的先验信息，并且被广泛地应用于大规模的社区检测网络中。这是理解图组织的一个关键方法，通常是其他分析的主要步骤。\n如何使用：Label Propagation具有不同的应用，例如了解社会团体中的共识形成、识别在生物网络的过程(功能模块)中所涉及的蛋白质集合等等。甚至还可以用于半监督和无监督的机器学习作为初始的预处理步骤。</p>\n<h3>11. Strongly Connected</h3>\n<p>做什么：定位节点组，其中每个节点可从同一组中的所有其他节点按照关系的方向到达，常被应用于深度优先算法。\n如何使用：Strongly Connected通常用于在识别的集群上独立运行其他算法。作为有向图的预处理步骤，它有助于快速识别不连通的集群。\n在零售推荐中，它有助于识别具有强亲和性的组，然后将向那些尚未购买商品的群体推荐首选商品。</p>\n<h3>12. Union-Find/Connected Components/Weakly Connected</h3>\n<p>做什么：查找节点组，其中每个节点可从同一组中的任何其他节点到达，而不考虑关系的方向。它提供几乎恒定的时间操作(独立于输入大小)来添加新的组，合并现有的组，并确定两个节点是否在同一组中。\n如何使用：Union-find/connected 经常与其他算法结合使用，特别是对于高性能分组。作为无向图的预处理步骤，它有助于快速识别断开的组。</p>\n<h3>13. Louvain Modularity</h3>\n<p>做什么：通过比较它的关系密度与适当定义的随机网络来测量社团分组的质量(即假定的准确性)。它通常用于评估复杂网络的组织和社区层次结构。这对于无监督机器学习中的初始数据预处理也是有用的。\n如何使用：Louvain用于评估Twitter，LinkedIn和YouTube上的社交结构;用于欺诈分析，以评估一个组织是只存在一些不良行为，还是背后一个连环欺诈。Louvain在比利时电信网络中揭示了一个六级客户层级。</p>\n<h3>14. Local Clustering Coefficient/Node Clustering Coefficient</h3>\n<p>做什么：对于一个特定的节点，量化了其到邻居节点的距离， (每个节点都直接连接到其他节点)。例如，如果您的所有朋友都直接了解对方，那么您的本地集群系数将是1。集群的小值表明尽管存在一个分组，但节点之间并没有紧密连接。\n如何使用：Local cluster coefficient通过理解群体相关性或碎片化的可能性，对估计弹性具有重要意义。用这种方法对欧洲电网的分析发现，与稀疏连接的节点相比，集群更能抵御普遍的故障。</p>\n<h3>15. Triangle-Count and Average Clustering Coefficient</h3>\n<p>做什么：测量有多少节点具有三角形以及节点倾向于聚集在一起的程度。平均聚类系数为1时表明有一个分组，0时没有连接。为使聚类系数有意义，它应该明显高于网络中所有关系随机的版本。\n如何使用：平均聚类系数通常用于估计网络是否可能展现基于紧密集群的“小世界”行为。这也是集群稳定性和弹性的一个因素。流行病学家使用平均聚类系数来帮助预测不同社区的各种感染率。</p>\n<h2>结论</h2>\n<p>世界是由关系驱动的，而Neo4j图形分析揭示了图形背后的意义，希望这些优化的图形算法能够帮助你以更加有意义、更有效的方式来理解所连接的数据。</p>\n</div>","title":"Neo4j中的15种不同图算法及其功能","last_reply_at":"2025-10-20T13:41:00.883Z","good":false,"top":false,"reply_count":0,"visit_count":2638,"create_at":"2025-10-20T13:41:00.883Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"686f1befa8f5aea0094a7c67","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h1>Neo4j 企业版 vs 社区版对比（ 基于Neo4j 4.x）</h1>\n<p>参考官方：\n<a href=\"https://neo4j.com/docs/operations-manual/4.4/introduction/\">https://neo4j.com/docs/operations-manual/4.4/introduction/</a>\n基于Neo4j 5.x 参考官方：\n<a href=\"https://neo4j.com/docs/operations-manual/5/introduction/\">https://neo4j.com/docs/operations-manual/5/introduction/</a>\n<a href=\"https://neo4j.com/docs/operations-manual/5/database-internals/store-formats/#high-limit-format\">https://neo4j.com/docs/operations-manual/5/database-internals/store-formats/#high-limit-format</a></p>\n<h2>1. 核心功能对比</h2>\n<table>\n<thead>\n<tr>\n<th><strong>功能</strong></th>\n<th><strong>社区版</strong></th>\n<th><strong>企业版</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>属性图模型</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>原生图处理与存储</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>符合ACID原则的事务</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>密码图查询语言</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>带有语法高亮功能的Neo4j浏览器</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>Bolt协议</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>C#、Go、Java、JavaScript和Python的语言驱动[1]</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>高性能原生API</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>高性能缓存</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>基于成本的查询优化器</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>支持人工智能计划的图算法[1]</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>通过原生标签索引实现快速写入</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>组合索引</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>全文节点和关系索引</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>存储副本</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>空间的自动复用</td>\n<td>✔️ 支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>多个数据库（超出系统和默认数据库范围）</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>槽式和流水线式Cypher运行时</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>属性存在性约束</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>节点键约束</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>列出并终止正在运行的查询</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>基于角色的访问控制</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>子图访问控制</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>LDAP与Active Directory集成</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>Kerberos安全选项</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n</tbody>\n</table>\n<h2>2. 性能与扩展性</h2>\n<table>\n<thead>\n<tr>\n<th><strong>特性</strong></th>\n<th><strong>社区版</strong></th>\n<th><strong>企业版</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>全局应用的因果集群</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>簇内加密</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>离线备份</td>\n<td>✔️  支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>在线备份</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>加密备份</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>滚动升级</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>自动缓存预热</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>使用Neo4j驱动进行路由和负载均衡</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>高级监控(Neo4j Ops Manager、Prometheus)</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>图形大小限制</td>\n<td>340亿个节点，340亿条关系，以及680亿个属性</td>\n<td>无限制</td>\n</tr>\n<tr>\n<td>导入命令行工具（neo4j-admin import 命令）</td>\n<td>✔️  支持</td>\n<td>✔️  支持</td>\n</tr>\n<tr>\n<td>导入命令行工具（neo4j-admin import 命令），可恢复</td>\n<td>❌ 不支持</td>\n<td>✔️  支持</td>\n</tr>\n</tbody>\n</table>\n<h2>3. 安全与合规</h2>\n<table>\n<thead>\n<tr>\n<th><strong>特性</strong></th>\n<th><strong>社区版</strong></th>\n<th><strong>企业版</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>角色访问控制(RBAC)</td>\n<td>❌ 仅基础用户/密码认证</td>\n<td>✔️ 细粒度权限管理</td>\n</tr>\n<tr>\n<td>数据加密</td>\n<td>❌ 仅传输加密(TLS)</td>\n<td>✔️ 传输+静态加密</td>\n</tr>\n<tr>\n<td>审计日志</td>\n<td>❌ 无</td>\n<td>✔️ 完整操作记录</td>\n</tr>\n<tr>\n<td>LDAP/AD集成</td>\n<td>❌ 不支持</td>\n<td>✔️ 支持</td>\n</tr>\n<tr>\n<td>合规认证</td>\n<td>❌ 无</td>\n<td>✔️ SOC2, GDPR等</td>\n</tr>\n</tbody>\n</table>\n<h2>4. 运维与管理</h2>\n<table>\n<thead>\n<tr>\n<th><strong>特性</strong></th>\n<th><strong>社区版</strong></th>\n<th><strong>企业版</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Neo4j Browser</td>\n<td>✔️ 完整功能</td>\n<td>✔️ 完整功能</td>\n</tr>\n<tr>\n<td>Neo4j Bloom</td>\n<td>❌ 不包含</td>\n<td>✔️ 包含可视化工具</td>\n</tr>\n<tr>\n<td>Neo4j Desktop</td>\n<td>✔️ 支持</td>\n<td>✔️ 支持</td>\n</tr>\n<tr>\n<td>官方技术支持</td>\n<td>❌ 仅社区论坛</td>\n<td>✔️ 24/7 SLA</td>\n</tr>\n<tr>\n<td>升级与补丁</td>\n<td>❌ 依赖社区发布</td>\n<td>✔️ 优先获取</td>\n</tr>\n</tbody>\n</table>\n<h2>5. 授权与成本</h2>\n<table>\n<thead>\n<tr>\n<th><strong>特性</strong></th>\n<th><strong>社区版</strong></th>\n<th><strong>企业版</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>许可证</td>\n<td>GPLv3 开源(免费)</td>\n<td>商业许可证(按核心/年收费)</td>\n</tr>\n<tr>\n<td>云部署</td>\n<td>❌ 需自行部署</td>\n<td>✔️ 支持Neo4j AuraDB</td>\n</tr>\n<tr>\n<td>商业用途</td>\n<td>✔️ 允许(需遵守GPL条款)</td>\n<td>✔️ 允许</td>\n</tr>\n</tbody>\n</table>\n<h2>6. 适用场景推荐</h2>\n<h3>选择企业版当您需要：</h3>\n<p>✅ 生产环境高可用  （如集群部署 故障自动转移、读写分离）\n✅ 企业级安全与合规\n✅ TB级大规模数据处理  （如集群部署 数据库分片扩展）\n✅ 官方技术支持服务\n✅ 需要7×24小时在线不中断，包括备份\n✅ 需要权限、角色管理\n✅ 需要完善的审计日志\n✅ 需要完善的监控功能</p>\n<h3>选择社区版当您需要：</h3>\n<p>✅ 个人学习/开发测试\n✅ 小型项目 无集群的单实例项目\n✅ 零预算的起步阶段\n✅ 能接受停机备份\n✅ 无需权限、角色管理\n✅ 对审计日志要求不高</p>\n<blockquote>\n<p><strong>提示</strong>：企业版提供30天免费试用，可通过<a href=\"https://neo4j.com/download/\">官网</a>申请体验完整功能。</p>\n</blockquote>\n</div>","title":"neo4j 企业版 和 社区版 对比","last_reply_at":"2025-07-10T01:48:31.077Z","good":false,"top":false,"reply_count":0,"visit_count":7677,"create_at":"2025-07-10T01:48:31.077Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"686b8f2ea8f5aea0094a7c66","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/modeling-tips/\">https://neo4j.com/docs/getting-started/data-modeling/modeling-tips/</a></p>\n<h1>图数据建模技巧</h1>\n<h2>目标</h2>\n<p>在本指南中，您将找到一些有助于为您的领域设计数据模型的实用信息。优化模型可以帮助开发人员最大化系统和查询的性能。</p>\n<hr>\n<h2>建模技巧和方法</h2>\n<p>正如您在阅读建模指南或自己进行图数据建模时可能发现的那样，没有绝对正确或错误的建模方式。一些方式可能更适合您的需求，并在您优先考虑的方面表现更好，但您有多种选择。</p>\n<p>为了找到最适合您需求的数据模型，通常可以采用一些技术并根据分析结果做出数据模型决策。接下来的段落中，我们将讨论一些建模技巧和方法，帮助您选择适合的数据模型。</p>\n<hr>\n<h3>1. 先编写查询</h3>\n<p>了解您希望从数据中提出的问题和查询类型，是确定数据模型结构的绝佳方法。如果您知道查询需要在特定日期范围内返回结果，那么您可能需要确保日期不是节点上的属性，而是存储为单独的节点或关系。相比之下，对于大学课程领域，寻找与当前课程类似的课程可能更适合使用高层次的类别层次结构，这样可以更高效地搜索主题内的所有课程。</p>\n<p>即使您尚未确定确切的查询语法，理解您正在构建的系统或应用程序的意图，并围绕业务需求构建模型，将帮助您以更准确的方式组织数据。</p>\n<hr>\n<h3>2. 优先考虑查询</h3>\n<p>找到适合每个查询或功能的完美模型是非常困难的（甚至是不可能的）。正如我们在建模设计指南中讨论的那样，选择一种特定模型而不是另一种（或使用多种模型）会有权衡。虽然您可能会改善某些方面，但无法获得适合所有情况的解决方案。</p>\n<p>相反，您应该确定哪个模型最适合您的需求。您可能无法在每个单独查询上都达到性能最大化，但您可以通过某些资源、时间和代码从系统中获得最大收益。</p>\n<p>为此，您需要决定哪些查询必须绝对具有最高性能，以及哪些功能对于提供价值至关重要。这可能是一个艰难的决定，但无论您使用哪种技术，这些决策都会以某种形式存在。Neo4j 的优势在于其模型灵活性，可以随着优先级的变化进行调整。</p>\n<hr>\n<h3>3. 测试模型</h3>\n<p>在设计阶段，您可能会遇到未意识到的场景。找到这些场景的最佳方法之一是实际测试模型。</p>\n<p>加载部分数据并在系统上执行测试和查询，可以确定您收到的结果是否符合您的需求或预期性能。同样，Neo4j 的灵活性使您可以调整模型或优化查询以微调输出。</p>\n<p>在多个模型之间难以决定？尝试为每个模型创建概念验证测试，并同时测试它们的运行情况。哪些模型复杂或不值得麻烦？是否有一个模型在实际运行中表现更好，或者多数据模型方法是否真正提供了最佳结果？有时，找到答案的最佳方法是使用实时数据进行测试。</p>\n<hr>\n<h3>4. 重构图模型</h3>\n<p>如上所述以及其他指南中提到的，使用 Neo4j 时始终可以进行更改。数据模型设计为灵活且易于调整，正是出于这个原因。业务需求和优先级往往会波动。用户行为也可能发生变化，从而导致业务的转变。</p>\n<p>Cypher® 允许您编写查询以对标签进行批量更新、添加或删除属性，以及向结构中插入额外的节点和关系。此外，还有一些程序可以帮助批量查询和更新集群实例。</p>\n<p>有关此主题的更多信息，请查看 <a href=\"https://neo4j.com/labs/apoc/\">APOC 库</a>！</p>\n<hr>\n<h3>其他注意事项</h3>\n<p>数据集的大小也会影响查询和性能。如果您的数据集较小，那么在执行更复杂的查询时可能不会看到太大的性能影响。只有当数据量增长时，您才可能看到影响增加。这时，数据模型和查询优化对于最大化系统价值变得至关重要。</p>\n</div>","title":"Neo4j官方教程：第25节，图数据建模技巧","last_reply_at":"2025-07-07T09:11:10.243Z","good":true,"top":false,"reply_count":0,"visit_count":3312,"create_at":"2025-07-07T09:11:10.243Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"686b8eaaa8f5aea0094a7c65","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/relational-to-graph-modeling/\">https://neo4j.com/docs/getting-started/data-modeling/relational-to-graph-modeling/</a></p>\n<h1>从关系型数据模型到图数据模型的建模</h1>\n<p>对于有关系型数据建模背景的人来说，本指南将帮助您将现有的关系型数据建模知识转化为图数据建模知识。它将帮助您比较和对比两种建模过程的步骤，并帮助您识别两种数据库类型在数据建模方面的相似点和不同点。</p>\n<hr>\n<h2>简介</h2>\n<p>如果您熟悉关系型数据模型（包括表、列、关系基数等组件），那么图数据建模不会显得完全陌生。数据模型的设计仍然需要基于访问需求、查询需求、性能预期和业务逻辑。然而，图数据模型的结构略有不同。</p>\n<p>您可能有一个全新的项目，想要创建图数据模型，但只熟悉如何创建关系型模型。或者您可能已经有一个现有的关系型模型项目，想要将其转换为图模型。无论哪种情况，本指南都将利用您对关系型数据模型的现有知识，教您如何创建图数据模型。</p>\n<hr>\n<h2>关系型与图数据库架构</h2>\n<p>快速回顾一下，关系型数据库依赖索引查找和表连接来连接不同的实体。这在性能方面很快会成为问题，尤其是当有多个表连接、表中有数百万行或查询复杂且需要通过子查询遍历多个层级时。</p>\n<p>在概念页面的示例中，要找到 Alice 所属的部门，您需要查询 <code>Person</code> 表以找到代表 Alice 的行，该行与唯一 ID（主键）绑定。然后，查询需要访问关联实体表（<code>Person_Dept</code>），以找到她的 ID 与一个或多个部门 ID 的关联。最后，查询需要检查 <code>Department</code> 表，以找到关联实体表中部门 ID 的实际值。</p>\n<p>下图回顾了我们刚刚描述的示例：</p>\n<h3>关系型模型示例</h3>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/relational_model.svg\" alt=\"image\">\n<strong>图 1. 关系型模型 - <code>Person</code> 和 <code>Department</code> 表</strong></p>\n<p>在图数据库中，您无需担心表连接和索引查找，因为图数据是通过每个单独实体及其与其他实体的关系来构建的。</p>\n<p>那么，我们如何从创建关系型数据模型转向图数据模型呢？</p>\n<hr>\n<h2>数据模型转换技巧</h2>\n<p>以下是将关系型数据模型的关键组件转换为图数据模型组件的一些技巧。帮助您将关系型图表转换为图模型的步骤如下：</p>\n<ol>\n<li><strong>表到节点标签</strong> - 关系型模型中的每个实体表变成图模型中的节点标签。</li>\n<li><strong>行到节点</strong> - 关系型实体表中的每一行变成图中的一个节点。</li>\n<li><strong>列到节点属性</strong> - 关系型表中的列（字段）变成图中的节点属性。</li>\n<li><strong>仅保留业务主键</strong> - 删除技术主键，仅保留业务主键。</li>\n<li><strong>添加约束/索引</strong> - 为业务主键添加唯一约束，为频繁查找的属性添加索引。</li>\n<li><strong>外键到关系</strong> - 将指向其他表的外键替换为关系，然后删除外键。</li>\n<li><strong>移除默认值</strong> - 删除具有默认值的数据，无需存储这些值。</li>\n<li><strong>清理数据</strong> - 去除规范化表中的重复数据，将其提取到单独的节点以获得更清晰的模型。</li>\n<li><strong>索引列到数组</strong> - 索引列名（如 <code>email1</code>, <code>email2</code>, <code>email3</code>）可能表示数组属性。</li>\n<li><strong>连接表到关系</strong> - 连接表转换为关系，表中的列变成关系属性。</li>\n</ol>\n<p>如果将上述列表中的项目应用到我们寻找 Alice 所属部门的示例中，我们可以得到如下图所示的图模型：</p>\n<h3>图模型示例</h3>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/relational_graph_model-arr.svg\" alt=\"image\">\n<strong>图 2. 图模型 - Alice 和三个部门作为节点</strong></p>\n<p>虽然两种模型都有类似之处，例如通过表结构或标签对数据进行分类，但图模型不会将数据限制在预定义的严格表/列布局中。我们将在下一节中查看另一个示例。</p>\n<hr>\n<h2>组织领域数据模型</h2>\n<p>为了让我们有另一个练习机会，我们将使用一个标准的组织领域，并展示它在关系型数据库和图数据库中的建模方式。您可以尝试自己创建图数据模型，然后看看它与示例模型的相似程度。</p>\n<h3>关系型组织结构图</h3>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/relational_org_chart.svg\" alt=\"image\">\n<strong>图 3. 组织领域 - 关系型模型</strong></p>\n<hr>\n<h3>转换步骤</h3>\n<ol>\n<li>首先，我们可以通过颜色将表分类为主域表和关联实体表。然后，我们可以将表名转换为节点标签。在这种情况下，<code>Project</code>、<code>Person</code>、<code>Department</code> 和 <code>Organization</code> 成为图模型中的标签。</li>\n<li>表中的行变成它们自己的节点，行中的列变成节点上的属性。例如，<code>Person</code> 表中的一行将变成一个节点，节点上的属性包括姓名和出生日期。任何允许多个相似值的索引列将变成数组（例如 <code>skill1</code>, <code>skill2</code>, <code>skill3</code> 列转换为节点上的数组属性）。</li>\n<li>如果有任何技术主键（即仅为了使行唯一而创建的主键，例如 <code>project_id</code>），则删除这些主键，仅保留业务需求所需的属性。还需要为业务主键添加唯一约束，以确保数据库不会允许重复。</li>\n<li>外键用于关系型连接查找的，转换为关系，因为它们显示了节点之间的链接。连接表（或关联实体表）也变成关系，连接表中的列移动到关系属性。</li>\n<li>由于 Neo4j 仅存储所需属性，因此无需存储空值和默认值，因此可以删除关系型模型中创建的任何默认值。</li>\n<li>最后，任何为规范化表或为简化而去规范化创建的重复数据都需要删除，因为在图模型中不需要这些数据。</li>\n</ol>\n<p>经过此过程后，您的图数据模型应类似于下图所示：</p>\n<h3>图组织结构图</h3>\n<p><strong>图 4. 组织领域 - 图模型</strong></p>\n<hr>\n<h2>总结</h2>\n<p>在开始导入数据之前，了解图模型的基本概念非常重要，因为随着需求的变化，调整模型或填充模型会变得更加容易。在即将发布的指南中，您将看到图数据的建模如何影响查询、性能和模型变化。</p>\n</div>","title":"Neo4j官方教程：第24节，从关系型数据模型到图数据模型的建模","last_reply_at":"2025-07-07T09:08:58.341Z","good":true,"top":false,"reply_count":0,"visit_count":3554,"create_at":"2025-07-07T09:08:58.341Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"686b8d6da8f5aea0094a7c64","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/versioning/\">https://neo4j.com/docs/getting-started/data-modeling/versioning/</a></p>\n<h1>版本控制</h1>\n<p>每次重构数据模型时，都会创建新的版本。跟踪数据结构的变化或显示当前和过去的值对于审计目的、趋势分析等非常有价值。本页面概述了可以用来跟踪随时间变化的数据的不同建模方式。</p>\n<hr>\n<h2>实体的版本控制</h2>\n<p>通过对相关实体进行版本控制，可以跟踪数据的变化。这种策略在以下情况下非常有用：</p>\n<ul>\n<li>访问图中特定实体（例如节点）的多个版本（例如产品在不同时间的名称）。</li>\n<li>仅检索最新版本（例如产品的当前名称）。</li>\n</ul>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/versioned-entities.svg\" alt=\"image\"></p>\n<h3>示例：图中显示实体的不同版本，其属性值随时间变化</h3>\n<ul>\n<li><strong>实体版本控制的特点：</strong>\n<ul>\n<li>实体 <code>Product</code> 通过显式关系链接到其不同版本。</li>\n<li>实体 <code>Product</code> 是不可变的。只有存储在不同版本（<code>State</code> 节点）中的属性会发生变化。</li>\n<li><code>LATEST</code> 关系将实体 <code>Product</code> 链接到其最新版本（<code>State</code>），该版本也是版本 2（<code>V2</code>）。</li>\n</ul>\n</li>\n</ul>\n<h3>优缺点</h3>\n<table>\n<thead>\n<tr>\n<th>优点</th>\n<th>缺点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>建模、查询和维护简单。</td>\n<td>更新节点需要删除 <code>LATEST</code> 关系，并创建实体与其最新版本之间的新关系。</td>\n</tr>\n<tr>\n<td>对最终用户显式，无需任何转换。</td>\n<td>如果不使用其他版本控制模式，可能会受到限制，因为如果不是最新版本，可能很难知道要检索哪个版本。</td>\n</tr>\n</tbody>\n</table>\n<h3>查询示例</h3>\n<p>以下是使用实体版本控制策略的常见查询示例：</p>\n<h4>获取 ID 为 ‘1’ 的产品版本 2 的名称</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Product {id:1})-[:V2]-&gt;(s:State)\nRETURN s.name\n</code></pre><h4>获取 ID 为 ‘1’ 的产品最新版本的名称</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Product {id:1})-[:LATEST]-&gt;(s:State)\nRETURN s.name\n</code></pre><hr>\n<h2>基于时间的实体版本控制</h2>\n<p>实体版本控制的一种变体是基于时间的方法。这在以下情况下非常有用：</p>\n<ul>\n<li><strong>图快照</strong>：通过检索图中某个时间点的所有有效元素（节点和关系）（例如，2023 年 6 月 12 日星期一可用的产品）。</li>\n<li><strong>图差异</strong>：比较两个不同时间戳的图快照（例如，哪些节点被添加、哪些被删除、哪些保持不变）。</li>\n<li><strong>时间序列遍历</strong>：仅遍历图中某个时间点的有效元素（节点或关系），以找到连接基于时间事件的关系的时间顺序（例如，带有车站之间的行程关系的共享单车图）。</li>\n<li><strong>图历史</strong>：建模数据变化的历史。\n<img src=\"https://neo4j.com/docs/getting-started/_images/time-based-entities.svg\" alt=\"image\"></li>\n</ul>\n<h3>示例：基于时间的实体版本控制</h3>\n<ul>\n<li><strong>基于时间的版本控制特点：</strong>\n<ul>\n<li>每个元素都有专门的 <code>validFrom</code>/<code>validTo</code> 时间属性。</li>\n<li>节点只有在其有效时间范围重叠时才能共享关系。</li>\n<li>信息可能会重复。</li>\n<li>图的完整历史可用。</li>\n</ul>\n</li>\n</ul>\n<h3>优缺点</h3>\n<table>\n<thead>\n<tr>\n<th>优点</th>\n<th>缺点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>每个元素都有明确的时间间隔，在该时间间隔内元素有效。</td>\n<td>如果节点状态发生变化，节点必须被复制，并分配新的有效时间间隔。</td>\n</tr>\n<tr>\n<td>状态绑定到特定元素（无需额外关系）。</td>\n<td>更新节点需要创建连接到新节点/状态的新关系，并分配新的有效时间间隔。</td>\n</tr>\n<tr>\n<td>可以聚合所有元素（或某个时间点的有效元素）。</td>\n<td>数据重复无法避免。</td>\n</tr>\n</tbody>\n</table>\n<h3>查询示例</h3>\n<p>以下是使用基于时间的实体版本控制策略的常见查询示例：</p>\n<h4>获取产品 “Rice Cooker” 的当前价格</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Product)\nWHERE p.name = &quot;Rice Cooker&quot; AND p.validTo = ∞\nRETURN p.price\n</code></pre><h4>获取产品 “Rice Cooker” 在 11 月的价格</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Product)\nWHERE p.name = &quot;Rice Cooker&quot;\nAND datetime(p.validFrom) &lt;= datetime(&quot;November&quot;) &lt;= datetime(p.validTo)\nRETURN p.price\n</code></pre><h4>获取当前产品目录及价格</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH ()-[r:HAS_PRODUCT]-&gt;(p)\nWHERE r.validTo = ∞\nRETURN p.name, p.price\n</code></pre><hr>\n<h2>链表</h2>\n<p>链表是一种建模策略，当对象的顺序很重要时非常有用。</p>\n<h3>链表的用途：</h3>\n<ul>\n<li>事件顺序，例如获取银行账户执行的交易顺序。</li>\n<li>基于关系获取列表中的前一个和下一个元素（例如播放列表中的下一首歌曲，或撤销文本文档中的操作）。\n<img src=\"https://neo4j.com/docs/getting-started/_images/linked-list-versioning.svg\" alt=\"image\"></li>\n</ul>\n<h3>示例：使用链表模型设计进行版本控制</h3>\n<ul>\n<li><strong>链表特点：</strong>\n<ul>\n<li>实体 <code>Product</code> 链接到序列的第一个元素，也可以链接到最后一个元素。</li>\n<li>与实体版本控制一样，实体 <code>Product</code> 在此处也是不可变的。</li>\n<li>序列中的每个元素通过 <code>NEXT</code> 关系链接到下一个元素。</li>\n</ul>\n</li>\n</ul>\n<h3>优缺点</h3>\n<table>\n<thead>\n<tr>\n<th>优点</th>\n<th>缺点</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>使用关系获取下一个/前一个元素效率高。</td>\n<td>如果不使用其他版本控制模式，可能仅限于非常具体的用例。</td>\n</tr>\n<tr>\n<td>建模和维护简单。</td>\n<td>很难找到不是第一个或最后一个的特定版本。</td>\n</tr>\n<tr>\n<td>对最终用户显式。</td>\n<td>-</td>\n</tr>\n</tbody>\n</table>\n<h3>查询示例</h3>\n<p>以下是使用链表版本控制策略的常见查询示例：</p>\n<h4>获取产品 “Professional chair” 的下一个名称</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:State{name: &quot;Professional chair&quot;})-[:NEXT]-&gt;(s:State)\nRETURN s.name\n</code></pre><h4>获取 ID 为 ‘1’ 的产品的前一个名称</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Product {id:1})-[:LAST]-&gt;(:State)&lt;-[:NEXT]-(s:State)\nRETURN s.name\n</code></pre><hr>\n<h2>时间线树</h2>\n<p>如建模设计中所述，时间线树是一种常见的建模设计。当您想要跟踪变化时，它可以是一种有用的策略。在此示例中，时间线结构从年份扩展到天，其余的非时间数据节点是图中包含重要数据的节点。\n<img src=\"https://neo4j.com/docs/getting-started/_images/timeline-tree.svg\" alt=\"image\"></p>\n<h3>示例：图中显示两个不同的时间线按年份划分</h3>\n<h4>查询示例</h4>\n<p>如果您想找到某个时间段内发生的所有购买，例如 2012 年 12 月的所有购买，可以从 2012 年导航到 12 月，然后从该分支下的所有叶节点（没有后代的节点）中获取数据：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (root:Timeline)-[:IN_YEAR]-&gt;(year:Year {value:2012})-[:IN_MONTH]-&gt;(month:Month {value:12})\nWITH month\nMATCH (month)-[:ON_DAY]-&gt;(day)\nMATCH (purchase:Purchase)-[:OCCURRED]-&gt;(day)\nRETURN purchase\n</code></pre><hr>\n<h2>组合方法</h2>\n<p>一些复杂的用例需要结合上述一种或多种建模技术，因为每种技术都有其优点和缺点。</p>\n<h3>示例：结合时间线树的更复杂版本控制方法</h3>\n<ul>\n<li>具体组合取决于用例。</li>\n<li>应考虑查询时间和事务频率等因素。</li>\n</ul>\n</div>","title":"Neo4j官方教程：第23节，版本控制","last_reply_at":"2025-07-07T09:03:41.998Z","good":true,"top":false,"reply_count":0,"visit_count":2966,"create_at":"2025-07-07T09:03:41.998Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"5af6db359662eee704f31c92","author_id":"5aa77f3f51bad0a10b198ac0","tab":"ask","content":"<div class=\"markdown-text\"><p>最好是Java的</p>\n</div>","title":"请问 没有将sparql语句转换成cypher语句的工具？","last_reply_at":"2025-06-23T03:17:04.972Z","good":false,"top":false,"reply_count":2,"visit_count":4544,"create_at":"2018-05-12T12:16:53.444Z","author":{"loginname":"butchercode","avatar_url":"https://avatars0.githubusercontent.com/u/28502818?v=4&s=120"}},{"id":"6833c811b13f67342db8ad6c","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><h3>安装LangChain 依赖</h3>\n<pre class=\"prettyprint language-shell\"><code>pip install --upgrade --quiet  langchain langchain-community langchain-openai neo4j\n</code></pre><h3>安装Neo4j</h3>\n<p><a href=\"https://neo4j.com/deployment-center/\">https://neo4j.com/deployment-center/</a> 下载安装 neo4j-community-5.26.4 解压到任意目录</p>\n<h3>安装Neo4j Apoc 插件</h3>\n<p><a href=\"https://github.com/neo4j/apoc/releases?page=1\">https://github.com/neo4j/apoc/releases?page=1</a> 下载安装apoc-5.26.6-core.jar\n复制到neo4j安装目录 plugins目录下\n修改Neo4j配置文件，启用Neo4j Apoc 插件：到neo4j安装目录 plugins目录下修改\\conf\\neo4j.conf，添加如下两行</p>\n<pre class=\"prettyprint\"><code>dbms.security.procedures.unrestricted=apoc.*\ndbms.security.procedures.allowlist=apoc.*\n</code></pre><h3>启动Neo4j</h3>\n<p>命令行到neo4j安装目录\\bin下运行：</p>\n<pre class=\"prettyprint language-shell\"><code>neo4j console\n</code></pre><h3>langchain + deepseek +neo4j 构建电影知识图谱智能问答</h3>\n<pre class=\"prettyprint language- python\"><code>import getpass\nimport os\nfrom langchain.chains import GraphCypherQAChain\nfrom langchain_openai import ChatOpenAI\nfrom langchain_community.graphs import Neo4jGraph\n\nos.environ[&quot;OPENAI_API_KEY&quot;] = &quot;您的DeepSeek API 秘钥&quot;\nos.environ[&quot;NEO4J_URI&quot;] = &quot;bolt:&#x2F;&#x2F;localhost:7687&quot;\nos.environ[&quot;NEO4J_USERNAME&quot;] = &quot;neo4j&quot;\nos.environ[&quot;NEO4J_PASSWORD&quot;] = &quot;您的Neo4j密码&quot;\n\nllm = ChatOpenAI(\n    model=&#x27;deepseek-chat&#x27;,\n    base_url=&quot;https:&#x2F;&#x2F;api.deepseek.com&#x2F;v1&quot;\n)\n\ngraph = Neo4jGraph()\n\n# Import movie information\n\nmovies_query = &quot;&quot;&quot;\nLOAD CSV WITH HEADERS FROM \n&#x27;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;tomasonjo&#x2F;blog-datasets&#x2F;main&#x2F;movies&#x2F;movies_small.csv&#x27; \nAS row\nMERGE (m:Movie {id:row.movieId})\nSET m.released = date(row.released),\n    m.title = row.title,\n    m.imdbRating = toFloat(row.imdbRating)\nFOREACH (director in split(row.director, &#x27;|&#x27;) | \n    MERGE (p:Person {name:trim(director)})\n    MERGE (p)-[:DIRECTED]-&gt;(m))\nFOREACH (actor in split(row.actors, &#x27;|&#x27;) | \n    MERGE (p:Person {name:trim(actor)})\n    MERGE (p)-[:ACTED_IN]-&gt;(m))\nFOREACH (genre in split(row.genres, &#x27;|&#x27;) | \n    MERGE (g:Genre {name:trim(genre)})\n    MERGE (m)-[:IN_GENRE]-&gt;(g))\n&quot;&quot;&quot;\n#用Loadcsv 在线下载并构建电影知识图谱数据\n\ngraph.query(movies_query)\ngraph.refresh_schema() #刷新schema\n\n\nchain = GraphCypherQAChain.from_llm(graph=graph,allow_dangerous_requests=True,llm=llm, verbose=True)\nresponse = chain.invoke({&quot;query&quot;: &quot;电影《Casino》的演员阵容是怎样的？&quot;}) #提问\nprint(response) #回答\n</code></pre><p>回答如下：</p>\n<pre class=\"prettyprint language-shell\"><code>\u001b[1m&gt; Entering new GraphCypherQAChain chain...\u001b[0m\nGenerated Cypher:\n\u001b[32;1m\u001b[1;3mMATCH (p:Person)-[:ACTED_IN]-&gt;(m:Movie {title: &#x27;Casino&#x27;}) RETURN p.name\u001b[0m\nFull Context:\n\u001b[32;1m\u001b[1;3m[{&#x27;p.name&#x27;: &#x27;James Woods&#x27;}, {&#x27;p.name&#x27;: &#x27;Joe Pesci&#x27;}, {&#x27;p.name&#x27;: &#x27;Robert De Niro&#x27;}, {&#x27;p.name&#x27;: &#x27;Sharon Stone&#x27;}]\u001b[0m\n\n\u001b[1m&gt; Finished chain.\u001b[0m\n{&#x27;query&#x27;: &#x27;电影《Casino》的演员阵容是怎样的？&#x27;, &#x27;result&#x27;: &#x27;电影《Casino》的演员阵容包括詹姆斯·伍兹（James Woods）、乔·佩西（Joe Pesci）、罗伯特·德尼罗（Robert De Niro）和莎朗·斯通（Sharon Stone）。&#x27;}\n</code></pre></div>","title":"Langchain + deepseek +neo4j 构建电影知识图谱智能问答","last_reply_at":"2025-05-26T01:46:57.860Z","good":true,"top":false,"reply_count":0,"visit_count":3281,"create_at":"2025-05-26T01:46:57.860Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"682700deb13f67342db8ad69","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/modeling-designs/\">https://neo4j.com/docs/getting-started/data-modeling/modeling-designs/</a></p>\n<h3>数据建模设计</h3>\n<p>在本节中，您将学习如何使用各种建模决策来表示图数据。数据模型的构建方式会影响查询和性能。我们的目标是教您如何评估模型并进行适当的更改，以便为您的用例定义最佳解决方案并最大化查询性能。</p>\n<h3>为什么数据模型很重要</h3>\n<p>与任何数据库一样，您设计的数据模型对确定查询逻辑和数据存储结构都很重要。这种实践也适用于图数据库，但有一个例外：Neo4j 是无模式的，这意味着您的数据模型可以随业务需求轻松调整和变化。</p>\n<h4>常见场景</h4>\n<ul>\n<li>需要收集新字段并进行新分析？</li>\n<li>需要改变对客户或其他实体的解释方式并修改其定义？</li>\n<li>法规要求系统减少信息采集或限制可读性（更改数据格式/类型）？</li>\n</ul>\n<p>您可能在一家公司工作过，其中每个区域或部门对领域的定义都不同。以通用客户域为例：对于业务内的不同区域，客户可以被定义为不同类型的个体。这些定义也可能随时间变化，或者公司可能决定统一各部门之间客户的含义。</p>\n<h3>Neo4j的优势</h3>\n<p>如果您使用过其他类型的数据库，您会熟悉这些场景所涉及的开发和管理工作。然而，Neo4j允许您轻松地对图的局部或整体进行详细和广泛的更改：</p>\n<ul>\n<li>支持随时间推移的小规模更改</li>\n<li>支持包含实体多种所需信息的广泛定义</li>\n</ul>\n<p>开发人员和架构师只需要确定：</p>\n<ol>\n<li>数据模型的结构</li>\n<li>如何定义用于查询的实体</li>\n</ol>\n<h3>属性与关系的对比</h3>\n<p>在早期设计决策中，您可能会遇到是将某些内容建模为：</p>\n<ul>\n<li>节点上的属性</li>\n<li>还是与独立节点的关系</li>\n</ul>\n<p>例如，可以将电影类型作为 Movie 节点上的属性进行建模。</p>\n<p>这种设计选择将影响：</p>\n<ul>\n<li>查询的编写方式</li>\n<li>遍历图数据的性能</li>\n<li>数据的维护和扩展性</li>\n</ul>\n<p>在接下来的内容中，我们将介绍查看不同数据集的几种方法，并展示每种方法如何影响图数据的查询和遍历性能。\n<img src=\"https://neo4j.com/docs/getting-started/_images/modeling_genre_property-arr.svg\" alt=\"image\"></p>\n<p>编写查询来查找特定电影的类型是很简单的。只需找到想要了解的 Movie 节点，然后返回 genre 属性中列出的值。但是，要找出共享类型的电影，需要一个更复杂的查询来：</p>\n<ol>\n<li>查找每个 Movie 节点</li>\n<li>遍历每个电影的类型属性数组</li>\n<li>与第二部电影的类型属性数组中的每个值进行比较</li>\n</ol>\n<p>这会影响性能（嵌套循环和节点属性比较），查询也会更加复杂。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;查找特定电影的类型\nMATCH (m:Movie {title:&quot;The Matrix&quot;})\nRETURN m.genre;\n\n&#x2F;&#x2F;查找共享类型的电影\nMATCH (m1:Movie), (m2:Movie)\nWHERE any(x IN m1.genre WHERE x IN m2.genre)\nAND m1 &lt;&gt; m2\nRETURN m1, m2;\n</code></pre><p>现在，相反，如果您将电影及其类型建模为单独的节点，并在它们之间创建一种关系，您将得到如图2所示的模型。\n<img src=\"https://neo4j.com/docs/getting-started/_images/modeling_genre_node-arr.svg\" alt=\"image\">\n这将为流派创建一个完全独立的实体(节点)，允许您将所有具有共享流派的电影连接到该流派节点。让我们看看这如何改变我们的查询。为了找到特定电影的流派，它首先需要找到它正在寻找的电影节点(在本例中为“矩阵”)，然后找到通过IN_GENRE关系连接到该电影的节点。</p>\n<p>最大的区别在于第二个查询的语法，该查询用于查找哪些电影具有相同的类型。它比我们早期的版本简单得多，因为它使用自然的图形模式(实体-关系-实体)来查找所需的信息。首先，Cypher找到一部电影及其相关的类型，然后寻找同一类型的第二部电影。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;find the genres for a particular movie\nMATCH (m:Movie {title:&quot;The Matrix&quot;}),\n      (m)-[:IN_GENRE]-&gt;(g:Genre)\nRETURN g.name;\n\n&#x2F;&#x2F;find which movies share genres\nMATCH (m1:Movie)-[:IN_GENRE]-&gt;(g:Genre),\n      (m2:Movie)-[:IN_GENRE]-&gt;(g)\nRETURN m1, m2, g\n</code></pre><p>数据模型的版本没有好坏之分，但是“最佳”选项很大程度上取决于您打算对数据运行的查询类型。</p>\n<p>如果您计划对单个项目进行分析，并且只返回关于该实体的详细信息(比如特定电影的类型)，那么第一个数据模型将非常适合您的需求。但是，如果您需要运行分析来寻找实体之间的共同点或者查看一组节点，那么第二个数据模型肯定会提高这些类型的查询的性能。</p>\n<h3>复杂数据结构</h3>\n<p>众所周知，不是所有的数据模型都简单直接。数据是混乱的，模型必须尝试更好地组织它以帮助我们看到模式并做出决策。</p>\n<p>漫威漫画数据是一个难以建模的复杂数据结构的典型例子。在漫威宇宙中，漫画中有角色出场或担任主角。漫画可以按特定时间的故事线或叙事组织成系列，重大事件可能发生在定义角色路径或系列的漫画中。创作者（包括作家、插画师等）是漫画的作者，定义故事线、角色改编和发生的事件。多个创作者也可以互换参与创作漫画或系列。</p>\n<p>这个数据集已经看起来很复杂，有多个实体和关系在起作用。在尝试对这里存在的层次结构和中间实体进行建模时，又增加了一层复杂性。</p>\n<p>如果您有时间，可以在 Vimeo 上观看 Peter 演讲的完整视频链接，但我们想强调 Peter 在数据集中讨论的两个关键挑战。</p>\n<p>首先，他发现漫画角色往往极其动态。许多角色无法通过名字、服装或任何特定属性来识别，因为这些都经常变化。</p>\n<p>其次，Peter 发现了时序问题。对于漫画宇宙的新手来说，有些人可能想确定从哪里开始或接下来看哪些漫画。然而，漫画期刊并不总是按顺序编号的，甚至有些故事情节会跨越多个系列来回出现。这使得分离某些故事块或事件以及角色的演绎变得极其困难。</p>\n<h3>示例：中间节点</h3>\n<p>在这个模型中有用的一种建模技术是超边的概念。超边通常用于建模存在于两个以上实体之间的关系。Neo4j 不支持两个以上节点之间的关系，而是使用中间节点来建模这种关系。它们通常用于表示多个实体在某个时间点的连接。</p>\n<p>这方面的一个常见例子是大学课程。同一门课程可能有多个开设班次，使用相同的教师在相同的建筑物中等。课程的每个部分（或开设班次）就成为课程的一个实例。</p>\n<p>Marvel 的 Peter 处理他们数据中的中间节点的方式是创建一个 Appearance 节点，该节点表示特定时间点上 Person 和 Alias 的交集。这个 Appearance 可以关联到多个 Moment 节点，在这些节点中人物和化身作为一个整体出现。这在下面的模型中表示（也在视频中）。\n<img src=\"https://neo4j.com/docs/getting-started/_images/modeling_marvel_hyperedge_appearance-arr.svg\" alt=\"image\">\n在关系型存储中，试图对所有这些复杂方面进行分类和关联将极其困难，并进一步使整体数据的分析和审查变得复杂。图模型允许他们对这个高度动态的宇宙进行建模，并跟踪其数据中所有不断变化的连接。对于这个用例，图是完美的选择。</p>\n<h3>时间绑定数据和版本控制</h3>\n<p>建模时间特定数据和关系的一种方式是在关系类型中包含数据。由于 Neo4j 专门针对实体之间的关系遍历进行了优化，因此您通常可以通过将日期指定为关系类型并仅遍历特定日期的关系来提高查询性能。</p>\n<p>一个常见的例子是对航空公司航班进行建模。航空公司在特定日期有从特定地点到特定地点的航班。我们可以从下面的图 4 所示的模型开始，展示航班如何在机场之间运行。\n<img src=\"https://neo4j.com/docs/getting-started/_images/modeling_airport_flights-arr.svg\" alt=\"image\">\n我们很快就会意识到，我们需要对存在于两个目的地之间的飞行实体进行建模，因为多架飞机可以在一天内多次往返于两个目的地之间。</p>\n<p>然而，您的查询可能仍然显示了该模型在过滤特定机场的所有航班方面的弱点——特别是对于伦敦和其他主要城市，这些城市在任何时间跨度内都有数百个航班连接到某个机场节点。检查每个航班节点的几个属性在资源上可能是昂贵的。</p>\n<p>如果我们要为特定的机场日创建一个节点，并在类型中创建一个带有日期的关系，那么我们可以编写查询来查找任何指定日期(或日期范围)从机场起飞的航班。这样，您就不需要检查每个航班与机场的关系。相反，你只会关注那些你在乎的日期的关系。这个模型结果如下图所示。\n<img src=\"https://neo4j.com/docs/getting-started/_images/modeling_airport_flight_dates-arr.svg\" alt=\"image\">\n版本控制类似于上面的模型，我们创建了一个日期关系类型，我们也可以用它来跟踪数据的版本。跟踪数据结构的变化或显示当前和过去的值对于审计、趋势分析等非常重要。</p>\n<p>例如，如果您想在一个人和他的当前地址之间创建一个新的有生效日期的关系，但是还想保留过去的地址，那么您可以使用相同的原则在关系类型中包含一个日期。为了找到这个人的当前地址，查询将查找最近的关系。</p>\n<p>有时，您可能会发现一个模型对于您需要的一个场景确实很好，但是另一个模型对于其他场景更好。例如，一些模型可以更好地处理写查询，而另一些模型可以更好地处理读查询。这两种能力对您的用例都很重要，那么您会怎么做呢？</p>\n<p>在这些情况下，您可以将这两种模式结合起来，利用各自的优势。是的，您可以在您的图表中使用多个数据模型！</p>\n<p>代价是现在您需要维护两个模型。每当您创建一个新的节点或关系，或者更新图的一部分时，您都需要进行更改以适应这两种模型。这也会影响查询性能，因为更新每个模型可能需要两倍的语法。</p>\n<p>虽然这肯定是一个可能的选择，但是您应该知道维护成本，并评估这些成本是否能够被您将看到的每个所需查询的性能改进所抵消。如果是这样，能够使用多个数据模型是一个很好的解决方案！</p>\n</div>","title":"Neo4j官方教程：第22节，数据建模设计","last_reply_at":"2025-05-16T09:09:50.219Z","good":true,"top":false,"reply_count":0,"visit_count":2814,"create_at":"2025-05-16T09:09:50.219Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"6826fa35b13f67342db8ad68","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/tutorial-refactoring/\">https://neo4j.com/docs/getting-started/data-modeling/tutorial-refactoring/</a></p>\n<h3>教程：重构图数据模型</h3>\n<p>重构是更改数据模型和图的过程。需要重构数据模型的主要原因包括：</p>\n<ul>\n<li>当前建模的图无法覆盖所有用例</li>\n<li>出现了新的用例</li>\n<li>用例的 Cypher® 查询在图扩展时性能不佳</li>\n</ul>\n<p>为了满足这些需求，本教程将指导您设计、实现和测试一个经过重构的数据模型，并更新 Cypher 查询。</p>\n<h3>前置条件</h3>\n<p>本教程是《教程：创建图数据模型》的后续内容。在继续之前，您需要完成该教程中创建的数据模型。</p>\n<p>或者，您也可以现在从头开始创建。选择您喜欢的部署方法，并使用以下代码添加数据：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (Apollo13:Movie {title: &#x27;Apollo 13&#x27;, tmdbID: 568, released: &#x27;1995-06-30&#x27;, imdbRating: 7.6, genres: [&#x27;Drama&#x27;, &#x27;Adventure&#x27;, &#x27;IMAX&#x27;]})\nCREATE (TomH:Person {name: &#x27;Tom Hanks&#x27;, tmdbID: 31, born: &#x27;1956-07-09&#x27;})\nCREATE (MegR:Person {name: &#x27;Meg Ryan&#x27;, tmdbID: 5344, born: &#x27;1961-11-19&#x27;})\nCREATE (DannyD:Person {name: &#x27;Danny DeVito&#x27;, tmdbID: 518, born: &#x27;1944-11-17&#x27;})\nCREATE (JackN:Person {name: &#x27;Jack Nicholson&#x27;, tmdbID: 514, born: &#x27;1937-04-22&#x27;})\nCREATE (SleeplessInSeattle:Movie {title: &#x27;Sleepless in Seattle&#x27;, tmdbID: 858, released: &#x27;1993-06-25&#x27;, imdbRating: 6.8, genres: [&#x27;Comedy&#x27;, &#x27;Drama&#x27;, &#x27;Romance&#x27;]})\nCREATE (Hoffa:Movie {title: &#x27;Hoffa&#x27;, tmdbID: 10410, released: &#x27;1992-12-25&#x27;, imdbRating: 6.6, genres: [&#x27;Crime&#x27;, &#x27;Drama&#x27;]})\n\nMERGE (TomH)-[:ACTED_IN {roles:&#x27;Jim Lovell&#x27;}]-&gt;(Apollo13)\nMERGE (TomH)-[:ACTED_IN {roles:&#x27;Sam Baldwin&#x27;}]-&gt;(SleeplessInSeattle)\nMERGE (MegR)-[:ACTED_IN {roles:&#x27;Annie Reed&#x27;}]-&gt;(SleeplessInSeattle)\nMERGE (DannyD)-[:DIRECTED]-&gt;(Hoffa)\nMERGE (DannyD)-[:ACTED_IN {roles:&#x27;Robert &quot;Bobby&quot; Ciaro&#x27;}]-&gt;(Hoffa)\nMERGE (JackN)-[:ACTED_IN {roles:&#x27;Hoffa&#x27;}]-&gt;(Hoffa)\n\nCREATE (Sandy:User {name: &#x27;Sandy Jones&#x27;, userID: 1})\nCREATE (Clinton:User {name: &#x27;Clinton Spencer&#x27;, userID: 2})\n\nMERGE (Sandy)-[:RATED {rating:5}]-&gt;(Apollo13)\nMERGE (Sandy)-[:RATED {rating:4}]-&gt;(SleeplessInSeattle)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(Apollo13)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(SleeplessInSeattle)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(Hoffa)\n</code></pre><h3>剩余或新用例</h3>\n<p>假设您想知道有哪些电影可以用某种语言观看。</p>\n<p>要回答这个问题，您需要先将此信息添加到图中。然而，添加新数据会带来重复的风险，进而影响图的性能。</p>\n<p>为演示这种情况，向 ‘Movie’ 节点添加新的 languages 属性及其对应值：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (Apollo13:Movie {title:&#x27;Apollo 13&#x27;})\nMATCH (SleeplessInSeattle:Movie {title:&#x27;Sleepless in Seattle&#x27;})\nMATCH (Hoffa:Movie {title:&#x27;Hoffa&#x27;})\nSET Apollo13.languages = [&#x27;English&#x27;]\nSET SleeplessInSeattle.languages = [&#x27;English&#x27;]\nSET Hoffa.languages = [&#x27;English&#x27;, &#x27;Italian&#x27;, &#x27;Latin&#x27;]\n</code></pre><p>结果：\n<img src=\"https://neo4j.com/docs/getting-started/_images/movie-languages.svg\" alt=\"image\">\n要检索所有英语电影，执行此查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWHERE &#x27;English&#x27; IN m.languages\nRETURN m.title\n</code></pre><p>结果将返回电影 “Apollo 13”、“Sleepless in Seattle” 和 “Hoffa”。</p>\n<p>此查询检索所有 Movie 节点然后测试 languages 属性是否包含值 English。这种方法没错，但随着图的扩展可能遇到两个问题：</p>\n<ol>\n<li>查询必须检索所有 Movie 节点 → 随着图的扩展，这种建模方式会降低查询性能</li>\n<li>language 属性值在多个 Movie 节点中重复 → 如果多个节点共享相同的属性值，说明该属性值可以作为新实体（如节点或关系）</li>\n</ol>\n<p>解决方案是将 languages 属性重构为节点，并用新关系将其连接到 Movie 节点。\n现在：\n<img src=\"https://neo4j.com/docs/getting-started/_images/language-before.svg\" alt=\"image\">\n重构：\n<img src=\"https://neo4j.com/docs/getting-started/_images/language-after.svg\" alt=\"image\"></p>\n<h3>消除重复数据</h3>\n<p>要将节点属性 languages 重构为节点，可以使用以下查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWITH m, m.languages AS languages\nUNWIND languages AS language\nMERGE (l:Language {name: language})\nMERGE (m)-[:IN_LANGUAGE]-&gt;(l)\nREMOVE m.languages\n</code></pre><p>查询分解说明：</p>\n<ol>\n<li>UNWIND Movie 节点的 languages 属性，将其条目转换为新的 Language 节点</li>\n<li>创建 IN_LANGUAGE 关系连接 Movie 节点与其对应的 Language 节点</li>\n<li>移除 Movie 节点的 languages 属性\n如图：\n<img src=\"https://neo4j.com/docs/getting-started/_images/language-nodes.svg\" alt=\"image\">\n重构后，图中应只有一个值为 “English” 的 Language 节点，相关电影与其相连。这消除了大量重复并提高了图扩展时的性能。</li>\n</ol>\n<h3>处理复杂数据</h3>\n<p>假设出现了需要每部电影制片公司信息的新用例。制片公司数据包括物理地址，这可以视为复杂数据。</p>\n<p>可以通过创建 ProductionCompany 节点和地址属性将此信息添加到图中：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (p:ProductionCompany {name:&#x27;Imagine Entertainment&#x27;, country:&#x27;US&#x27;, postalCode:90212, state:&#x27;CA&#x27;, city:&#x27;Beverly Hills&#x27;, address1:&#x27;10351 Santa Monica Blvd&#x27;})\nMERGE (Apollo13:Movie {title:&#x27;Apollo 13&#x27;})\nCREATE (p)-[:PRODUCED]-&gt;(Apollo13)\nCREATE (jerseyFilms:ProductionCompany {name:&#x27;Jersey Films&#x27;, country:&#x27;US&#x27;, postalCode:90049, state:&#x27;CA&#x27;, city:&#x27;Los Angeles&#x27;, address1:&#x27;10351 Santa Monica Blvd&#x27;})\nMERGE (hoffa:Movie {title:&#x27;Hoffa&#x27;})\nCREATE (jerseyFilms)-[:PRODUCED]-&gt;(hoffa)\n</code></pre><p><img src=\"https://neo4j.com/docs/getting-started/_images/producers.svg\" alt=\"image\">\n在节点上存储复杂数据的问题\n以这种方式在节点上存储复杂数据可能存在以下问题：</p>\n<ol>\n<li>数据重复\n多个制片公司可能位于相同位置，导致信息在多个节点上重复\n示例：之前我们将’languages’属性重构为节点，就是为了避免&quot;English&quot;在所有 Movie 节点上重复</li>\n<li>过度获取\n查询节点信息时需要不必要地检索更多同类节点\n示例：要查找位于加利福尼亚的制片公司时，需要扫描所有 ProductionCompany 节点的属性来获取 state 值。而如果将加利福尼亚作为独立节点，就能提供更短的访问路径，避免获取多余信息\n替代方案：可以创建索引</li>\n</ol>\n<h4>数据建模目标</h4>\n<p>数据建模的核心目标是减少查询时需要访问的图数据量。如果出现以下情况，需要考虑重构模型：</p>\n<p>图中包含大量重复数据\n查询仍在过度获取数据\n当前模型分析\n目前模型中新增了 ProductionCompany 节点标签，包含多个地址属性。这些属性值存在大量重复，不够理想。为提高效率，应：</p>\n<p>检查重复的键值\n考虑将其转换为新实体（节点或关系）\n重构示例\n由于两家制片公司都在加利福尼亚，可以：</p>\n<p>将州属性转换为 State 节点\n通过新的 LOCATED_AT 关系连接制片公司\n移除制片公司节点上的 state 属性\n重构效果\n按州查询制片公司时可直接基于 <a href=\"http://State.name\">State.name</a> 值过滤\n避免评估所有 ProductionCompany 节点的 state 属性\n<img src=\"https://neo4j.com/docs/getting-started/_images/california.svg\" alt=\"image\">\n总结\n处理复杂数据的重构方式取决于：</p>\n<p>需要解答的问题\n图扩展时查询的性能表现\n下一步是通过测试来衡量图中的性能表现。</p>\n<h3>使用特定关系</h3>\n<p>当项目有需要经常检索某些信息的重复用例时，可以使用特定关系作为重构策略。好处包括：</p>\n<ul>\n<li>减少需要检索的节点数量</li>\n<li>提高查询性能</li>\n</ul>\n<p>例如，如果经常需要检索 1995 年的演员信息，查询可以从：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-(m:Movie)\nWHERE p.name = &#x27;Tom Hanks&#x27; AND m.released STARTS WITH &#x27;1995&#x27;\nRETURN DISTINCT m.title AS Movie\n</code></pre><p>优化为：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN_1995]-(m:Movie)\nWHERE p.name = &#x27;Tom Hanks&#x27;\nRETURN m.title AS Movie\n</code></pre><h3>重新测试图</h3>\n<h3>重新测试图的用例查询</h3>\n<p>以下是需要重新检查的用例查询列表：</p>\n<h4>1. 哪些人参演了某部电影？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-&gt;(m:Movie {title:&#x27;Hoffa&#x27;})\nRETURN p\n</code></pre><h4>2. 谁导演了某部电影？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:DIRECTED]-&gt;(m:Movie {title:&#x27;Hoffa&#x27;})\nRETURN p\n</code></pre><h4>3. 某人参演了哪些电影？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name:&#x27;Tom Hanks&#x27;})-[:ACTED_IN]-&gt;(m:Movie)\nRETURN m\n</code></pre><h4>4. 有多少用户为某部电影评分？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie {title: &#x27;Apollo 13&#x27;})\nRETURN COUNT {(:User)-[:RATED]-&gt;(m)} AS &#96;Number of reviewers&#96;\n</code></pre><h4>5. 谁是某部电影中最年轻的演员？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-(m:Movie)\nWHERE m.title = &#x27;Hoffa&#x27;\nRETURN p.name AS Actor, p.born as &#96;Year Born&#96; \nORDER BY p.born DESC LIMIT 1\n</code></pre><h4>6. 某人在电影中扮演什么角色？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name:&#x27;Tom Hanks&#x27;})-[a:ACTED_IN]-&gt;(m:Movie {title: &#x27;Apollo 13&#x27;})\nRETURN a.roles\n</code></pre><h4>7. 某年按 IMDB 评分最高的电影是哪部？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWHERE m.released STARTS WITH &#x27;1995&#x27;\nRETURN m.title as Movie, m.imdbRating as Rating \nORDER BY m.imdbRating DESC LIMIT 1\n</code></pre><h4>8. 某演员参演了哪些剧情片？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-(m:Movie)\nWHERE p.name = &#x27;Tom Hanks&#x27; AND\n&#x27;Drama&#x27; IN m.genres\nRETURN m.title AS Movie\n</code></pre><h4>9. 哪些用户给某部电影打了5分？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (u:User)-[r:RATED]-(m:Movie)\nWHERE m.title = &#x27;Apollo 13&#x27; AND\nr.rating = 5\nRETURN u.name as Reviewer\n</code></pre><h4>10. 哪些电影是英语电影？</h4>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWHERE m.languages = &#x27;English&#x27;\nRETURN m.title as Movie in English\n</code></pre><h3>说明</h3>\n<p>需要检查以上每个查询，看是否可以利用重构后的数据模型进行优化。比如最后一个查询&quot;哪些电影是英语电影？“就可以使用新的 Language 节点和 IN_LANGUAGE 关系进行重写。\n重构后，应重新检查所有用例查询。例如用例&quot;哪些电影是英语的？”：</p>\n<p>重构前：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWHERE m.languages = &#x27;English&#x27;\nRETURN m.title as Movie in English\n</code></pre><p>重构后：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)-[:IN_LANGUAGE]-&gt;(l:Language)\nWHERE l.name = &#x27;English&#x27;\nRETURN m.title as Movie in English\n</code></pre><h3>性能检查</h3>\n<p>在实际应用中，特别是图完全扩展时，可以通过 PROFILE 检查新查询的性能改进：</p>\n<pre class=\"prettyprint language-cypher\"><code>PROFILE MATCH (n:Person)\nRETURN n\n</code></pre><p>结果：\n<img src=\"https://neo4j.com/docs/getting-started/_images/query-plan.svg\" alt=\"image\"></p>\n<h3>持续学习</h3>\n<p>大多数重构工作是为了重新利用或添加更多信息到图中。</p>\n<p>可以在 GraphAcademy 的 Graph Data Modeling Fundamentals 交互式课程中学习更多重构策略，如将 Person 节点拆分为 Actor 和 Director 节点、将 Movie 节点的 genre 属性转换为节点等。</p>\n</div>","title":"Neo4j官方教程：第21节，重构图数据模型","last_reply_at":"2025-05-16T08:41:25.211Z","good":true,"top":false,"reply_count":0,"visit_count":2339,"create_at":"2025-05-16T08:41:25.211Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"680df39fb13f67342db8ad62","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling/tutorial-data-modeling/\">https://neo4j.com/docs/getting-started/data-modeling/tutorial-data-modeling/</a></p>\n<h1>教程：创建图数据模型</h1>\n<p>本教程旨在帮助您根据预期用途对数据进行建模。您将使用电影示例数据集作为主要资源。</p>\n<p>有关数据建模基础的交互式课程，请参阅 <a href=\"https://neo4j.com/graphacademy/\">GraphAcademy</a>。</p>\n<hr>\n<h2>定义领域</h2>\n<p>在本教程中，您将使用电影示例数据集。领域包括电影、出演或导演电影的人，以及对电影进行评分的用户。通过这些实体之间的连接（关系），您可以发现领域中的洞察。</p>\n<hr>\n<h2>定义用例</h2>\n<p>在定义领域后，您需要确定应用程序的用例。换句话说，您需要回答哪些问题？</p>\n<p>您可以列出问题来帮助确定应用程序的用例。这些问题将帮助您定义应用程序的需求以及图中必须包含的数据。</p>\n<p>在本教程中，您的应用程序应能够回答以下问题：</p>\n<ul>\n<li>哪些人出演了一部电影？</li>\n<li>哪个人导演了一部电影？</li>\n<li>某人出演了哪些电影？</li>\n<li>有多少用户对一部电影进行了评分？</li>\n<li>谁是出演电影的最年轻的人？</li>\n<li>某人在电影中扮演了什么角色？</li>\n<li>根据 IMDb，某一年评分最高的电影是哪部？</li>\n<li>某演员出演了哪些剧情片？</li>\n<li>哪些用户给某部电影打了 5 分？</li>\n</ul>\n<hr>\n<h2>定义目的</h2>\n<p>在为应用程序设计图数据模型时，您可能需要数据模型和实例模型。</p>\n<h3>数据模型</h3>\n<p>数据模型描述了领域中的节点和关系，包括标签、类型和属性。它不包含任何数据，但显示了回答用例所需的信息。</p>\n<p>在此阶段，您可以选择使用无代码工具来可视化您的计划。例如，使用 <a href=\"https://arrows.app/\">Arrows.app</a>，您可以绘制包含节点标签、关系类型和属性的数据模型：</p>\n<p>示例数据模型包括表示人和电影的两个节点，通过两种关系连接。\n<img src=\"https://neo4j.com/docs/getting-started/_images/sample-data-model.svg\" alt=\"image\">\n根据示例领域和初始问题，您可以列出初始模型中需要的信息：</p>\n<ul>\n<li>区分出演电影、导演电影和评分电影的人。</li>\n<li>评分的内容、数量以及提交时间。</li>\n<li>演员在电影中扮演的角色及其年龄。</li>\n<li>电影的类型。</li>\n</ul>\n<p>注意，在模型中，标签、关系类型和属性键遵循特定语法。在 Cypher® 中，这些称为标识符，区分大小写，字符串值也区分大小写。</p>\n<p>推荐的命名规范：</p>\n<ul>\n<li><strong>标签</strong>：首字母大写，使用驼峰命名法（例如：<code>Person</code>、<code>Movie</code>、<code>ImdbUser</code>）。</li>\n<li><strong>关系类型</strong>：全大写，使用下划线分隔（例如：<code>DIRECTED</code>、<code>ACTED_IN</code>）。</li>\n<li><strong>属性键</strong>：不大写，使用驼峰命名法（例如：<code>name</code>、<code>userID</code>）。</li>\n</ul>\n<p>在创建初始模型时，专注于模型的高层设计，即实体如何连接。更详细的分配信息将在“定义实体”步骤中描述。</p>\n<h3>实例模型</h3>\n<p>实例模型是存储和处理实际数据的表示。您可以使用实例模型测试用例。</p>\n<p>要创建实例模型，您需要一些示例数据并将其加载到所选的部署中。以下是一个小型但具有代表性的数据集：\n<img src=\"https://neo4j.com/docs/getting-started/_images/instance-example.svg\" alt=\"image\"></p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (Apollo13:Movie {title: &#x27;Apollo 13&#x27;, tmdbID: 568, released: &#x27;1995-06-30&#x27;, imdbRating: 7.6, genres: [&#x27;Drama&#x27;, &#x27;Adventure&#x27;, &#x27;IMAX&#x27;]})\nCREATE (TomH:Person {name: &#x27;Tom Hanks&#x27;, tmdbID: 31, born: &#x27;1956-07-09&#x27;})\nCREATE (MegR:Person {name: &#x27;Meg Ryan&#x27;, tmdbID: 5344, born: &#x27;1961-11-19&#x27;})\nCREATE (DannyD:Person {name: &#x27;Danny DeVito&#x27;, tmdbID: 518, born: &#x27;1944-11-17&#x27;})\nCREATE (JackN:Person {name: &#x27;Jack Nicholson&#x27;, tmdbID: 514, born: &#x27;1937-04-22&#x27;})\nCREATE (SleeplessInSeattle:Movie {title: &#x27;Sleepless in Seattle&#x27;, tmdbID: 858, released: &#x27;1993-06-25&#x27;, imdbRating: 6.8, genres: [&#x27;Comedy&#x27;, &#x27;Drama&#x27;, &#x27;Romance&#x27;]})\nCREATE (Hoffa:Movie {title: &#x27;Hoffa&#x27;, tmdbID: 10410, released: &#x27;1992-12-25&#x27;, imdbRating: 6.6, genres: [&#x27;Crime&#x27;, &#x27;Drama&#x27;]})\n</code></pre><p>建议手动使用 Cypher 添加数据以练习数据建模。</p>\n<hr>\n<h2>定义实体</h2>\n<p>实例模型帮助您预览数据将如何存储为节点、关系和属性。下一步是通过更多细节完善模型。</p>\n<h3>标签</h3>\n<p>应用程序用例中的主要名词在模型中表示为节点，并可用作节点标签。例如：</p>\n<ul>\n<li>哪些人出演了一部电影？</li>\n<li>有多少用户对一部电影进行了评分？</li>\n</ul>\n<p>初始模型中的节点为 <code>Person</code>、<code>Movie</code> 和 <code>User</code>。请注意，创建模型是一个迭代过程，经过重构后，模型可能会有所不同。</p>\n<h3>节点属性</h3>\n<p>您可以使用节点属性来：</p>\n<ul>\n<li>\n<p><strong>定位查询的起点</strong></p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Tom Hanks&#x27;})-[:ACTED_IN]-(m:Movie)\nRETURN m\n</code></pre></li>\n<li>\n<p><strong>遍历图</strong></p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-(m:Movie {title: &#x27;Apollo 13&#x27;})-[:RATED]-(u:User)\nRETURN p, u\n</code></pre></li>\n<li>\n<p><strong>返回查询数据</strong></p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Tom Hanks&#x27;})-[:ACTED_IN]-(m:Movie)\nRETURN m.title, m.released\n</code></pre></li>\n</ul>\n<p>以下是一些示例用例及其查询：</p>\n<table>\n<thead>\n<tr>\n<th>用例</th>\n<th>步骤</th>\n<th>查询示例</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>哪些人出演了一部电影？</td>\n<td>检索电影标题，返回演员姓名。</td>\n<td><code>MATCH (m:Movie {title:'Hoffa'})&lt;-[r:ACTED_IN]-(p:Person) RETURN p.name</code></td>\n</tr>\n<tr>\n<td>哪个人导演了一部电影？</td>\n<td>检索电影标题，返回导演姓名。</td>\n<td><code>MATCH (m:Movie {title:'Hoffa'})&lt;-[r:DIRECTED]-(p:Person) RETURN p.name</code></td>\n</tr>\n<tr>\n<td>某人出演了哪些电影？</td>\n<td>检索演员姓名，返回电影标题。</td>\n<td><code>MATCH (p:Person {name:'Tom Hanks'})-[:ACTED_IN]-&gt;(m:Movie) RETURN m.title</code></td>\n</tr>\n<tr>\n<td>谁是出演电影的最年轻的人？</td>\n<td>检索电影标题，评估演员年龄，返回最年轻演员姓名。</td>\n<td><code>MATCH (m:Movie {title:'Sleepless in Seattle'})&lt;-[r:ACTED_IN]-(p:Person) RETURN p.name, p.born ORDER BY p.born ASC LIMIT 1</code></td>\n</tr>\n<tr>\n<td>某一年 IMDb 评分最高的电影是哪部？</td>\n<td>检索某年发布的所有电影，评估 IMDb 评分，返回评分最高的电影标题。</td>\n<td><code>MATCH (m:Movie {release:date('1995')}) RETURN m.title, m.imdbRating ORDER BY m.imdbRating DESC LIMIT 1</code></td>\n</tr>\n</tbody>\n</table>\n<h3>唯一标识符</h3>\n<p>在 Cypher 中，可以创建两个具有完全相同数据的节点。然而，从数据管理和模型角度来看，不同的节点应包含不同的数据。您可以使用唯一标识符确保每个节点都是独立且可区分的实体。</p>\n<p>例如，<code>Movie.tmdbID</code> 是一个很好的唯一标识符，因为数据库中可能有不同的电影具有相同的标题，但 <code>tmdbID</code> 属性将不同，从而充当唯一标识符。</p>\n<p>建议通过使用唯一性约束来强制执行唯一标识符。有关更多信息，请参阅 <a href=\"https://neo4j.com/docs/cypher-manual/current/constraints/\">Cypher → 创建属性唯一性约束</a>.</p>\n<hr>\n<h2>关系</h2>\n<p>关系是节点之间的连接，这些连接是用例中的动词：</p>\n<ul>\n<li>哪些人出演了一部电影？</li>\n<li>哪些人导演了一部电影？</li>\n</ul>\n<h3>命名</h3>\n<p>为图中的关系选择好的名称（类型）非常重要，并尽可能具体，以便 Neo4j 仅遍历相关连接。</p>\n<p>例如，与其使用通用的关系类型（如 <code>CONNECTED_TO</code>），更倾向于使用更具体且直观的方式描述实体之间的连接。</p>\n<p>在本教程示例中，您可以定义以下关系：</p>\n<ul>\n<li><code>ACTED_IN</code></li>\n<li><code>DIRECTED</code></li>\n</ul>\n<h3>关系方向</h3>\n<p>所有关系必须有方向。在创建时，关系需要显式指定方向，或者通过模式的从左到右顺序推断方向。\n<img src=\"https://neo4j.com/docs/getting-started/_images/relationship-direction.svg\" alt=\"image\">\n在示例用例中，<code>ACTED_IN</code> 关系必须从 <code>Person</code> 节点指向 <code>Movie</code> 节点：</p>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (TomH)-[:ACTED_IN]-&gt;(Apollo13)\nMERGE (TomH)-[:ACTED_IN]-&gt;(SleeplessInSeattle)\nMERGE (MegR)-[:ACTED_IN]-&gt;(SleeplessInSeattle)\nMERGE (DannyD)-[:ACTED_IN]-&gt;(Hoffa)\nMERGE (DannyD)-[:DIRECTED]-&gt;(Hoffa)\nMERGE (JackN)-[:ACTED_IN]-&gt;(Hoffa)\n</code></pre><p><img src=\"https://neo4j.com/docs/getting-started/_images/relationships-graph.svg\" alt=\"image\"></p>\n<h3>关系属性</h3>\n<p>关系属性用于丰富两个节点之间的关系。当您需要知道两个节点之间的关系方式而不仅仅是它们存在关系时，可以使用关系属性进一步定义关系。\n<img src=\"https://neo4j.com/docs/getting-started/_images/relationship-roles.svg\" alt=\"image\">\n例如，问题“某人在电影中扮演了什么角色？”可以通过 <code>ACTED_IN</code> 关系中的属性 <code>roles</code> 来回答：</p>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (TomH)-[:ACTED_IN {roles:&#x27;Jim Lovell&#x27;}]-&gt;(Apollo13)\nMERGE (TomH)-[:ACTED_IN {roles:&#x27;Sam Baldwin&#x27;}]-&gt;(SleeplessInSeattle)\nMERGE (MegR)-[:ACTED_IN {roles:&#x27;Annie Reed&#x27;}]-&gt;(SleeplessInSeattle)\nMERGE (DannyD)-[:ACTED_IN {roles:&#x27;Robert &quot;Bobby&quot; Ciaro&#x27;}]-&gt;(Hoffa)\nMERGE (JackN)-[:ACTED_IN {roles:&#x27;Hoffa&#x27;}]-&gt;(Hoffa)\n</code></pre><p>查询示例：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name:&#x27;Tom Hanks&#x27;})-[r:ACTED_IN]-&gt;(m:Movie {title:&#x27;Apollo 13&#x27;})\nRETURN r.roles\n</code></pre><hr>\n<h2>添加更多数据</h2>\n<p>现在您已经创建了节点之间的初始连接，是时候向图中添加更多信息了。例如：</p>\n<ul>\n<li>有多少用户对一部电影进行了评分？</li>\n<li>哪些用户给某部电影打了 5 分？</li>\n</ul>\n<p>为此，您需要在图中添加用户及其评分信息，这意味着数据模型的更改。\n<img src=\"https://neo4j.com/docs/getting-started/_images/roles-graph.svg\" alt=\"image\"></p>\n<h3>添加用户节点</h3>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (Sandy:User {name: &#x27;Sandy Jones&#x27;, userID: 1})\nMERGE (Clinton:User {name: &#x27;Clinton Spencer&#x27;, userID: 2})\n</code></pre><p>建议将用户信息与演员和导演分开，因为它们与电影节点的关系不同。</p>\n<h3>添加评分关系</h3>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (Sandy)-[:RATED {rating:5}]-&gt;(Apollo13)\nMERGE (Sandy)-[:RATED {rating:4}]-&gt;(SleeplessInSeattle)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(Apollo13)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(SleeplessInSeattle)\nMERGE (Clinton)-[:RATED {rating:3}]-&gt;(Hoffa)\n</code></pre><h2><img src=\"https://neo4j.com/docs/getting-started/_images/user-ratings.svg\" alt=\"image\"></h2>\n<h2>测试模型</h2>\n<p>在填充图以实现数据模型并使用一小组测试数据后，您现在应该测试它以确保满足每个用例。</p>\n<p>例如，测试用例“哪些人出演了一部电影？”可以运行以下查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-(m:Movie)\nWHERE m.title = &#x27;Sleepless in Seattle&#x27;\nRETURN p.name\n</code></pre><p>测试时，请确保 Cypher 语句正确。错误的查询可能导致错误地认为数据模型失败。</p>\n<hr>\n<h2>重构</h2>\n<p>完成测试后，下一步是进行调整。有关说明，请参阅 <a href=\"https://neo4j.com/docs/graph-data-modeling/current/tutorials/refactoring/\">教程：重构</a>。</p>\n</div>","title":"Neo4j官方教程：第20节，创建图数据模型","last_reply_at":"2025-04-27T09:06:39.613Z","good":true,"top":false,"reply_count":0,"visit_count":2943,"create_at":"2025-04-27T09:06:39.613Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"680b51dfb13f67342db8ad61","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/data-modeling\">https://neo4j.com/docs/getting-started/data-modeling</a></p>\n<h1>图数据建模是什么？</h1>\n<p>数据建模是一种定义查询逻辑和存储数据结构的实践。一个设计良好的模型是充分利用图数据库优势的关键，因为它可以提高查询性能、支持灵活查询并优化存储。</p>\n<hr>\n<h1>如何创建图数据模型</h1>\n<p>要将数据组织成数据模型，首先需要思考你想回答哪些问题。</p>\n<p>例如，假设你为一家零售公司工作，并希望了解客户购买了哪些产品。为此，你需要：</p>\n<ol>\n<li><strong>拥有关于已售产品和购买它们的客户的数据</strong>：这个过程称为“实体提取”。</li>\n<li><strong>理解这些实体之间的关系</strong>。</li>\n<li><strong>思考需要提供哪些其他细节</strong>，即需要为这些实体添加哪些属性（例如客户姓名）。</li>\n<li><strong>可选：在创建模型之前，使用无代码数据建模工具可视化模型</strong>。</li>\n<li><strong>如果满意，可以开始将数据写入数据库</strong>。</li>\n</ol>\n<p>在这个虚构的场景中，你可以通过以下方式将信息添加到图中：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (c:Customer {name: &quot;John&quot;})\nCREATE (p:Product {name: &quot;Camera&quot;})\nCREATE (c)-[:BUYS]-&gt;(p)\n</code></pre><p>然后，你可以通过查询测试这个模型（例如，John 买了什么）：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (c:Customer {name: &quot;John&quot;})-[b:BUYS]-&gt;(p)\nRETURN p\n</code></pre><p>请记住，图数据建模是一个迭代的过程。你的初始图数据模型只是一个起点。随着你对用例的深入了解或用例的变化，模型需要进行调整。</p>\n<p>此外，你可能会发现，尤其是在图规模扩大时，需要重构模型以确保它与业务需求保持一致。</p>\n<hr>\n<h1>总结</h1>\n<p>创建数据模型的过程包括以下步骤：</p>\n<ol>\n<li><strong>理解领域并为应用程序定义具体的用例（问题）</strong>。</li>\n<li><strong>通过提取实体并决定它们之间的关系，开发初始图数据模型</strong>。</li>\n<li><strong>根据初始数据模型测试用例</strong>。</li>\n<li><strong>使用 Cypher® 创建包含测试数据的图</strong>。</li>\n<li><strong>测试用例，包括图的性能</strong>。</li>\n<li><strong>由于关键用例的变化或性能原因，重构图数据模型</strong>。</li>\n</ol>\n<hr>\n<h1>持续学习</h1>\n<p>如果想要更深入地学习数据建模，可以尝试以下资源：</p>\n<ul>\n<li><strong>GraphAcademy: 数据建模基础</strong>：注册一个交互式课程。</li>\n<li><strong>从关系型到图模型</strong>：学习如何将关系型数据转换为图数据模型。</li>\n<li><strong>数据建模工具</strong>：查看可用于创建数据模型的工具列表。</li>\n<li><strong>数据建模技巧</strong>：查看如何提高数据建模技能的建议。</li>\n<li><strong>建模设计</strong>：查看可用于项目策略的数据建模设计示例。</li>\n<li><strong>Neo4j GraphGists</strong>：查找 Neo4j 社区分享的图数据建模示例。</li>\n</ul>\n</div>","title":"Neo4j官方教程：第19节， 图数据建模是什么","last_reply_at":"2025-04-25T09:11:59.084Z","good":true,"top":false,"reply_count":0,"visit_count":2461,"create_at":"2025-04-25T09:11:59.084Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"6800a9ffa755994623e85dc9","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/resources/\">https://neo4j.com/docs/getting-started/cypher-intro/resources/</a></p>\n<h1>Cypher 资源</h1>\n<h2>Cypher 基础和文档</h2>\n<ul>\n<li><a href>GraphAcademy - Cypher 基础</a> - 60分钟内学习 Cypher</li>\n<li><a href>文档: Cypher 手册</a></li>\n<li><a href>Cypher 速查表</a></li>\n<li><a href>Neo4j 社区站点</a>: 提问和获取 Cypher 相关答案</li>\n</ul>\n<h2>面向 SQL 开发人员的 Cypher</h2>\n<ul>\n<li><a href>视频: SQL 到 Cypher</a></li>\n<li><a href>免费电子书: 面向 RDBMS 开发人员的图数据库</a></li>\n</ul>\n<h2>其他资源</h2>\n<ul>\n<li><a href>Medium博客: Cypher 优化</a></li>\n<li>Cypher 中处理日期和时间的博客系列:\n<ul>\n<li><a href>第1部分</a></li>\n<li><a href>第2部分</a></li>\n<li><a href>第3部分</a></li>\n</ul>\n</li>\n<li><a href>Mark Needham 的 Cypher 博客</a></li>\n<li><a href>Max De Marzi 的 Cypher 博客</a></li>\n<li><a href>Eve Freeman 教程: 使用 Cypher 构建 ACL</a></li>\n<li><a href>Neo4j Medium 博客频道</a></li>\n</ul>\n<h2>使用 GRAPHACADEMY 学习</h2>\n<p><img src alt=\"badge\"></p>\n<h3>Cypher 基础课程</h3>\n<p>本课程通过视频、测验和动手练习,用尽可能少的时间教您使用 Neo4j 强大的查询语言 Cypher 的基础知识。</p>\n<p><a href>使用 GraphAcademy 学习 Cypher</a></p>\n</div>","title":"Neo4j官方教程：第18节， Cypher 资源","last_reply_at":"2025-04-17T07:13:03.371Z","good":true,"top":false,"reply_count":0,"visit_count":2679,"create_at":"2025-04-17T07:13:03.371Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"6800a7d2a755994623e85dc8","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/load-csv/\">https://neo4j.com/docs/getting-started/cypher-intro/load-csv/</a></p>\n<h1>教程：导入数据</h1>\n<p>本教程演示如何使用 LOAD CSV 从 CSV 文件导入数据。</p>\n<p>通过组合 Cypher® 子句 LOAD CSV、MERGE 和 CREATE，您可以将数据导入到 Neo4j 中。LOAD CSV 允许您访问数据值并对其执行操作。</p>\n<h2>数据文件</h2>\n<p>在本教程中，您将从以下 CSV 文件导入数据：</p>\n<h3>persons.csv 内容:</h3>\n<pre class=\"prettyprint language-csv\"><code>id,name\n1,Charlie Sheen  \n2,Michael Douglas\n3,Martin Sheen\n4,Morgan Freeman\n</code></pre><p>persons.csv 文件包含 id 和 name 两列。每行代表一个人,具有唯一 id 和姓名。</p>\n<h3>movies.csv 内容:</h3>\n<pre class=\"prettyprint language-csv\"><code>id,title,country,year\n1,Wall Street,USA,1987\n2,The American President,USA,1995\n3,The Shawshank Redemption,USA,1994\n</code></pre><p>movies.csv 文件包含 id、title、country 和 year 列。每行代表一部电影,具有唯一 id、标题、原产国和发行年份。</p>\n<h3>roles.csv 内容:</h3>\n<pre class=\"prettyprint language-csv\"><code>personId,movieId,role\n1,1,Bud Fox\n3,1,Carl Fox \n2,1,Gordon Gekko\n3,2,A.J. MacInerney\n2,2,President Andrew Shepherd\n4,3,Ellis Boyd &#x27;Red&#x27; Redding\n</code></pre><p>roles.csv 文件包含 personId、movieId 和 role 列。每行代表一个角色，包含人物 id(来自 persons.csv)和电影 id(来自 movies.csv)的关系数据。</p>\n<h2>图模型</h2>\n<p>数据模型如下所示：</p>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/getting-started-load-csv01-arr.svg\" alt=\"image\">(插入图1)</p>\n<p>基于 CSV 文件数据的结果图：</p>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/getting-started-load-csv02-arr.svg\" alt=\"image\">(插入图2)</p>\n<h2>前提条件</h2>\n<p>本教程使用 Linux 或 macOS 压缩包安装。</p>\n<p>假设您的当前工作目录是压缩包安装的 &lt;neo4j-home&gt; 目录，且 CSV 文件位于默认导入目录中。</p>\n<p>其他安装的默认目录请参见操作手册 → 文件位置。</p>\n<p>导入位置可以通过操作手册 → server.directories.import 配置。</p>\n<h2>准备数据库</h2>\n<p>导入数据之前，您应该通过创建索引和约束来准备要使用的数据库。</p>\n<p>您应该通过在 Person 和 Movie 节点上创建约束来确保它们具有唯一的 id 属性。</p>\n<p>创建唯一约束也会隐式创建索引。通过为 id 属性建立索引，节点查找(如通过 MATCH)将快得多。</p>\n<p>另外，为 country 名称创建索引以实现快速查找也是个好主意。</p>\n<ol>\n<li>启动 neo4j：</li>\n</ol>\n<pre class=\"prettyprint language-bash\"><code>bin&#x2F;neo4j start\n</code></pre><p>默认用户名是 neo4j，密码是 neo4j。</p>\n<ol>\n<li>创建约束使每个 Person 节点具有唯一的 id 属性：</li>\n</ol>\n<p>使用 Neo4j Browser：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE CONSTRAINT personIdConstraint FOR (person:Person) REQUIRE person.id IS UNIQUE\n</code></pre><p>或使用 Neo4j Cypher Shell：</p>\n<pre class=\"prettyprint language-bash\"><code>bin&#x2F;cypher-shell --database=neo4j &quot;CREATE CONSTRAINT personIdConstraint FOR (person:Person) REQUIRE person.id IS UNIQUE&quot;\n</code></pre><ol>\n<li>创建约束使每个 Movie 节点具有唯一的 id 属性：</li>\n</ol>\n<p>使用 Neo4j Browser：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE CONSTRAINT movieIdConstraint FOR (movie:Movie) REQUIRE movie.id IS UNIQUE\n</code></pre><p>或使用 Neo4j Cypher Shell：</p>\n<pre class=\"prettyprint language-bash\"><code>bin&#x2F;cypher-shell --database=neo4j &quot;CREATE CONSTRAINT movieIdConstraint FOR (movie:Movie) REQUIRE movie.id IS UNIQUE&quot;\n</code></pre><ol>\n<li>为 Country 节点的 name 属性创建索引：</li>\n</ol>\n<p>使用 Neo4j Browser：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE INDEX FOR (c:Country) ON (c.name)\n</code></pre><p>或使用 Neo4j Cypher Shell：</p>\n<pre class=\"prettyprint language-bash\"><code>bin&#x2F;cypher-shell --database=neo4j &quot;CREATE INDEX FOR (c:Country) ON (c.name)&quot;\n</code></pre><h2>使用 LOAD CSV 导入数据</h2>\n<ol>\n<li>从 persons.csv 文件加载数据：</li>\n</ol>\n<p>使用 Neo4j Browser：</p>\n<pre class=\"prettyprint language-cypher\"><code>LOAD CSV WITH HEADERS FROM &quot;file:&#x2F;&#x2F;&#x2F;persons.csv&quot; AS csvLine\nCREATE (p:Person {id: toInteger(csvLine.id), name: csvLine.name})\n</code></pre><ol>\n<li>从 movies.csv 文件加载数据：</li>\n</ol>\n<pre class=\"prettyprint language-cypher\"><code>LOAD CSV WITH HEADERS FROM &quot;file:&#x2F;&#x2F;&#x2F;movies.csv&quot; AS csvLine\nMERGE (country:Country {name: csvLine.country})\nCREATE (movie:Movie {id: toInteger(csvLine.id), title: csvLine.title, year:toInteger(csvLine.year)})\nCREATE (movie)-[:ORIGIN]-&gt;(country)\n</code></pre><ol>\n<li>从 roles.csv 文件加载数据：</li>\n</ol>\n<pre class=\"prettyprint language-cypher\"><code>:auto LOAD CSV WITH HEADERS FROM &#x27;file:&#x2F;&#x2F;&#x2F;roles.csv&#x27; AS csvLine\nCALL {\n WITH csvLine\n MATCH (person:Person {id: toInteger(csvLine.personId)}), (movie:Movie {id: toInteger(csvLine.movieId)})\nCREATE (person)-[:ACTED_IN {role: csvLine.role}]-&gt;(movie)\n} IN TRANSACTIONS OF 2 ROWS\n</code></pre><h2>导入数据</h2>\n<p>使用以下命令检查具有关系的所有节点：</p>\n<p>使用 Neo4j Browser：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (n)-[r]-&gt;(m) RETURN n, r, m\n</code></pre><p>或使用 Neo4j Cypher Shell：</p>\n<pre class=\"prettyprint language-bash\"><code>bin&#x2F;cypher-shell --database=neo4j &#x27;MATCH (n)-[r]-&gt;(m) RETURN n, r, m&#x27;\n</code></pre><p>输出将显示所有节点及其关系。</p>\n</div>","title":"Neo4j官方教程：第17节， 导入数据","last_reply_at":"2025-04-17T07:03:46.501Z","good":true,"top":false,"reply_count":0,"visit_count":5160,"create_at":"2025-04-17T07:03:46.501Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67fcc77da755994623e85dc7","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/procedures-functions/\">https://neo4j.com/docs/getting-started/cypher-intro/procedures-functions/</a></p>\n<h1>如何扩展 Cypher</h1>\n<p>本指南介绍了如何创建、使用和部署用户定义的程序和函数，这是 Cypher®（Neo4j 的查询语言）的扩展机制。</p>\n<h2>扩展 Cypher</h2>\n<p>Cypher 是一种强大且富有表达力的语言，具有一流的图模式和集合支持。但有时您需要做更多的事情，如额外的图算法、并行化或自定义转换。</p>\n<p>Cypher 可以通过用户定义的程序和函数进行扩展，详见 Java 参考 → 用户定义程序和 Java 参考 → 用户定义函数。</p>\n<p>Neo4j 本身提供并使用自定义程序。Neo4j 浏览器公开的许多监控、自检和安全功能都是使用程序实现的。\n<img src=\"https://neo4j.com/docs/getting-started/_images/procedures-functions-bolt.jpg\" alt=\"image\"></p>\n<h2>Neo4j 中的程序和函数</h2>\n<ul>\n<li>函数是简单的计算/转换，返回单个值</li>\n<li>函数可以在任何表达式或谓词中使用</li>\n<li>程序是更复杂的操作，生成结果流</li>\n<li>程序可以生成、获取或计算数据，供 Cypher 查询的后续处理步骤使用</li>\n</ul>\n<p>要调用数据库中部署的程序，请使用 CALL 子句(详见 Cypher 手册 → CALL 程序)。</p>\n<h2>列出和使用 Neo4j 的函数和程序</h2>\n<p>Neo4j 带有多个内置程序。要了解更多信息，请参阅操作手册 → 程序。</p>\n<p>要列出 DBMS 中所有可用的函数和程序，使用以下 Cypher 命令：</p>\n<pre class=\"prettyprint language-cypher\"><code>SHOW FUNCTIONS\nSHOW PROCEDURES\n</code></pre><p>您可以参考 Cypher 速查表以快速了解如何使用这些命令。</p>\n<p>每个程序返回一列或多列数据。通过 YIELD 子句，可以选择这些列并设置别名，然后在 Cypher 查询中使用。</p>\n<p>像其他 Cypher 管理命令一样，SHOW PROCEDURES 可以与 Cypher 子句的子集一起使用，如下所示，我们按 ‘db.’ 前缀过滤并按名称排序返回结果：</p>\n<pre class=\"prettyprint language-cypher\"><code>SHOW PROCEDURES\nYIELD name, signature, description as text\nWHERE name STARTS WITH &#x27;db.&#x27;\nRETURN * ORDER BY name ASC\n</code></pre><p>下面是另一个示例，展示如何按选定的类别（例如包）对可用程序进行分组：</p>\n<pre class=\"prettyprint language-cypher\"><code>SHOW PROCEDURES \nYIELD name, signature, description\nRETURN split(name,&quot;.&quot;)[0..-1] AS package, count(*) AS count,\n       collect(split(name,&quot;.&quot;)[-1]) AS names\nORDER BY count DESC\n</code></pre><p>可用程序集取决于您的安装类型和配置设置。结果可能如下：</p>\n<table>\n<thead>\n<tr>\n<th>package</th>\n<th>count</th>\n<th>names</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>[“dbms”]</td>\n<td>20</td>\n<td>[“checkConfigValue”, “components”, “info”,…]</td>\n</tr>\n<tr>\n<td>[“db”]</td>\n<td>16</td>\n<td>[“awaitIndex”, “awaitIndexes”, “checkpoint”,…]</td>\n</tr>\n<tr>\n<td>[“db”,“stats”]</td>\n<td>6</td>\n<td>[“clear”, “collect”, “retrieve”,…]</td>\n</tr>\n<tr>\n<td>[“dbms”, “cluster”]</td>\n<td>6</td>\n<td>[“checkConnectivity”, “cordonServer”, “protocols”,…]</td>\n</tr>\n<tr>\n<td>[“db”, “index”, “fulltext”]</td>\n<td>4</td>\n<td>[“awaitEventuallyConsistentIndexRefresh”, “listAvailableAnalyzers”,…]</td>\n</tr>\n</tbody>\n</table>\n<p>用户定义的函数用 Java 编写，部署到数据库中，其调用方式与其他 Cypher 函数相同。可以开发和使用两种主要类型的函数：</p>\n<ul>\n<li>用户定义的标量函数</li>\n<li>用户定义的聚合函数</li>\n</ul>\n<p>详细信息请参见 Cypher 手册 → 用户定义函数。</p>\n<p>您可以将任何程序库部署到自管理服务器，以使用其他程序和函数。</p>\n<p>另请查看 Neo4j Java 参考中的程序部分。</p>\n<h2>部署程序和函数</h2>\n<p>如果您构建自己的程序或从社区项目下载程序，它们会打包在 JAR 文件中。您可以将该文件复制到 Neo4j 服务器的 $NEO4J_HOME/plugins 目录并重启。</p>\n<p>由于程序和函数使用低级 Java API，它们可以访问所有 Neo4j 内部组件以及文件系统和机器。这就是为什么您应该了解部署哪些程序以及原因。只安装来自可信源的程序。如果它们是开源的，请检查其源代码，最好自己构建。</p>\n<p>有关如何确保这些附加组件安全性的最佳实践，请参见操作手册 → 保护扩展。</p>\n<p>某些程序和函数可用于自管理的 Neo4j 企业版和社区版。\n本节中描述的自定义代码与 AuraDB 不兼容。\n在 Neo4j AuraDB 中，可用的程序和函数仅限于内置程序和函数以及 APOC Core 库的子集。</p>\n<h2>程序和函数库</h2>\n<p>APOC Core 库为您提供了一组有用的 Cypher 程序，以增强数据集成、图算法和数据转换等领域的功能。</p>\n<p>例如，用于格式化和解析不同分辨率时间戳的函数：</p>\n<pre class=\"prettyprint language-cypher\"><code>RETURN apoc.date.format(timestamp()) as time,\n       apoc.date.format(timestamp(),&#x27;ms&#x27;,&#x27;yyyy-MM-dd&#x27;) as date,\n       apoc.date.parse(&#x27;13.01.1975&#x27;,&#x27;s&#x27;,&#x27;dd.MM.yyyy&#x27;) as unixtime,\n       apoc.date.parse(&#x27;2017-01-05 13:03:07&#x27;) as millis\n</code></pre><table>\n<thead>\n<tr>\n<th>time</th>\n<th>date</th>\n<th>unixtime</th>\n<th>millis</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“2017-01-05 13:06:39”</td>\n<td>“2017-01-05”</td>\n<td>158803200</td>\n<td>1483621387000</td>\n</tr>\n</tbody>\n</table>\n<p>在我们的 Neo4j Labs 项目中，您可以找到由社区和员工构建的库集。看看已有的内容，很多需求已经被覆盖，例如：</p>\n<ul>\n<li>索引操作</li>\n<li>数据库/API 集成</li>\n<li>图重构</li>\n<li>导入和导出</li>\n<li>空间索引查找</li>\n<li>RDF 导入和导出</li>\n<li>等等</li>\n</ul>\n<p>社区和 Neo4j Labs 项目不受官方支持，我们不提供任何 SLA 或向后兼容性和弃用的保证。</p>\n<h2>开发自己的程序和函数</h2>\n<p>您可以在 Neo4j Java 参考中找到有关编写和测试程序的详细信息。</p>\n<p>示例 GitHub 存储库包含详细的文档和注释，您可以直接克隆并用作起点。</p>\n<p>以下是一些初步提示。</p>\n<p>用户定义的函数比较简单，让我们从它们开始：</p>\n<ul>\n<li><code>@UserFunction</code> 注解的公共 Java 类中的方法</li>\n<li>默认名称是包名.方法名</li>\n<li>返回单个值</li>\n<li>只读</li>\n</ul>\n<p>用户定义的程序类似：</p>\n<ul>\n<li><code>@Procedure</code> 注解的 Java 方法</li>\n<li>带有附加模式属性(READ, WRITE, DBMS)</li>\n<li>返回具有公共字段的简单对象的 Java 8 流</li>\n<li>这些字段名称转换为可用于 YIELD 的结果列</li>\n</ul>\n<p>这些特性对两者都有效：</p>\n<ul>\n<li>使用 <code>@Name</code> 注解的参数(带可选默认值)</li>\n<li>可以使用注入的 <code>@Context public GraphDatabaseService</code></li>\n<li>在 Cypher 语句的事务中运行</li>\n<li>支持的参数和结果类型有：Long、Double、Boolean、String、Node、Relationship、Path、Object</li>\n</ul>\n</div>","title":"Neo4j官方教程：第16节， 如何扩展 Cypher","last_reply_at":"2025-04-14T08:29:49.725Z","good":true,"top":false,"reply_count":0,"visit_count":2348,"create_at":"2025-04-14T08:29:49.725Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67fcc47aa755994623e85dc6","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/dates-datetimes-durations/\">https://neo4j.com/docs/getting-started/cypher-intro/dates-datetimes-durations/</a></p>\n<h1>日期、日期时间和持续时间</h1>\n<h2>创建和更新值</h2>\n<p>让我们首先创建一些具有 <code>Datetime</code> 属性的节点。我们可以通过执行以下 Cypher® 查询来执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>UNWIND [\n    { title: &quot;Cypher Basics I&quot;,\n      created: datetime(&quot;2019-06-01T18:40:32.142+0100&quot;),\n      datePublished: date(&quot;2019-06-01&quot;),\n      readingTime: {minutes: 2, seconds: 15} },\n    { title: &quot;Cypher Basics II&quot;,\n      created: datetime(&quot;2019-06-02T10:23:32.122+0100&quot;),\n      datePublished: date(&quot;2019-06-02&quot;),\n      readingTime: {minutes: 2, seconds: 30} },\n    { title: &quot;Dates, Datetimes, and Durations in Neo4j&quot;,\n      created: datetime(),\n      datePublished: date(),\n      readingTime: {minutes: 3, seconds: 30} }\n] AS articleProperties\n\nCREATE (article:Article {title: articleProperties.title})\nSET article.created = articleProperties.created,\n    article.datePublished = articleProperties.datePublished,\n    article.readingTime = duration(articleProperties.readingTime)\n</code></pre><p>在此查询中：</p>\n<ul>\n<li><code>created</code> 属性是一个 <code>DateTime</code> 类型，等于执行查询时的时间。</li>\n<li><code>date</code> 属性是一个 <code>Date</code> 类型，等于执行查询时的日期。</li>\n<li><code>readingTime</code> 是一个 <code>Duration</code> 类型，为 3 分 30 秒。</li>\n</ul>\n<p>也许我们想对此文章节点进行一些更改以更新 <code>datePublished</code> 和 <code>readingTime</code> 属性。</p>\n<p>我们已决定在下周而不是今天发布该文章，因此我们想进行更改。如果我们想使用支持的格式创建一个新的 <code>Date</code> 类型，我们可以使用以下查询来执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article {title: &quot;Dates, Datetimes, and Durations in Neo4j&quot;})\nSET article.datePublished = date(&quot;2019-09-30&quot;)\n</code></pre><p>但是，如果我们想基于不支持的格式创建 <code>Date</code> 类型怎么办？为此，我们将使用 APOC 库中的函数来解析字符串。</p>\n<p>以下查询将不支持的数据格式解析为基于毫秒的时间戳，从该时间戳创建一个 <code>Datetime</code>，然后从该 <code>Datetime</code> 创建一个 <code>Date</code>：</p>\n<pre class=\"prettyprint language-cypher\"><code>WITH apoc.date.parse(&quot;Sun, 29 September 2019&quot;, &quot;ms&quot;, &quot;EEE, dd MMMM yyyy&quot;) AS ms\nMATCH (article:Article {title: &quot;Dates, Datetimes, and Durations in Neo4j&quot;})\nSET article.datePublished = date(datetime({epochmillis: ms}))\n</code></pre><p>我们可以使用相同的方法来更新 <code>created</code> 属性。我们唯一需要更改的是我们不需要将 <code>Datetime</code> 类型转换为 <code>Date</code>：</p>\n<pre class=\"prettyprint language-cypher\"><code>WITH apoc.date.parse(&quot;25 September 2019 06:29:39&quot;, &quot;ms&quot;, &quot;dd MMMM yyyy HH:mm:ss&quot;) AS ms\nMATCH (article:Article {title: &quot;Dates, Datetimes, and Durations in Neo4j&quot;})\nSET article.created = datetime({epochmillis: ms})\n</code></pre><p>也许我们还决定阅读时间实际上将比我们最初想象的要多一分钟。我们可以使用以下查询更新 <code>readingTime</code> 属性：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article {title: &quot;Dates, Datetimes, and Durations in Neo4j&quot;})\nSET article.readingTime =  article.readingTime + duration({minutes: 1})\n</code></pre><h2>格式化值</h2>\n<p>现在我们要编写一个查询来返回我们的文章。我们可以通过执行以下查询来执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>表 1. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Dates, Datetimes, and Durations in Neo4j”</td>\n<td>2019-09-25T06:29:39Z</td>\n<td>2019-09-29</td>\n<td>P0M0DT270S</td>\n</tr>\n</tbody>\n</table>\n<p>如果我们想格式化这些值，我们可以使用 APOC 库中的时间函数。以下查询将每个时间类型格式化为更友好的格式：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nRETURN article.title AS title,\n       apoc.temporal.format(article.created, &quot;dd MMMM yyyy HH:mm&quot;) AS created,\n       apoc.temporal.format(article.datePublished,&quot;dd MMMM yyyy&quot;) AS datePublished,\n       apoc.temporal.format(article.readingTime, &quot;mm:ss&quot;) AS readingTime\n</code></pre><p>表 2. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Dates, Datetimes, and Durations in Neo4j”</td>\n<td>“25 September 2019 06:29”</td>\n<td>“29 September 2019”</td>\n<td>“04:30”</td>\n</tr>\n</tbody>\n</table>\n<h2>比较和过滤值</h2>\n<p>如果我们想根据这些时间值过滤我们的文章怎么办？</p>\n<p>让我们首先找到 2019 年 6 月 1 日发布的文章。以下查询执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE article.datePublished = date({year: 2019, month: 6, day: 1})\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>表 3. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Cypher Basics I”</td>\n<td>2019-06-01T18:40:32.142+01:00</td>\n<td>2019-06-01</td>\n<td>P0M0DT135S</td>\n</tr>\n</tbody>\n</table>\n<p>如果我们想找到 2019 年 6 月发布的所有文章怎么办？我们可以编写以下查询来执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE article.datePublished = date({year: 2019, month: 6})\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>如果我们运行此查询，我们将获得以下结果：</p>\n<p>表 4. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Cypher Basics I”</td>\n<td>2019-06-01T18:40:32.142+01:00</td>\n<td>2019-06-01</td>\n<td>P0M0DT135S</td>\n</tr>\n</tbody>\n</table>\n<p>这似乎不对 - 2019 年 6 月 2 日发布的 Cypher Basics II 文章呢？我们这里的问题是 <code>date({year: 2019, month:6})</code> 返回 2019-06-01，所以我们只找到了 2019 年 6 月 1 日发布的文章。</p>\n<p>我们需要调整我们的查询以查找 2019 年 6 月 1 日至 2019 年 7 月 1 日之间发布的文章。以下查询执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE date({year: 2019, month: 7}) &gt; article.datePublished &gt;= date({year: 2019, month: 6})\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>表 5. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Cypher Basics I”</td>\n<td>2019-06-01T18:40:32.142+01:00</td>\n<td>2019-06-01</td>\n<td>P0M0DT135S</td>\n</tr>\n<tr>\n<td>“Cypher Basics II”</td>\n<td>2019-06-02T10:23:32.122+01:00</td>\n<td>2019-06-02</td>\n<td>P0M0DT150S</td>\n</tr>\n</tbody>\n</table>\n<p>如果我们想根据 <code>created</code> 属性（存储 <code>Datetime</code> 值）进行过滤怎么办？我们需要在过滤 <code>Datetime</code> 值时采用与处理 <code>Date</code> 值相同的方法。以下查询查找 2019 年 7 月之后创建的文章：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE article.created &gt; datetime({year: 2019, month: 7})\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>表 6. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Dates, Datetimes, and Durations in Neo4j”</td>\n<td>2019-09-25T06:04:39.072Z</td>\n<td>2019-09-25</td>\n<td>P0M0DT210S</td>\n</tr>\n</tbody>\n</table>\n<p>最后过滤持续时间。我们可能对可以在 3 分钟或更短时间内阅读的文章感兴趣。</p>\n<p>我们将从以下查询开始：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE article.readingTime &lt;= duration(&quot;PT3M&quot;)\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>但是，该查询会导致以下输出：没有更改，没有记录。</p>\n<p>如果我们想比较持续时间，我们需要通过将这些持续时间添加到日期来进行比较。我们并不真正关心查询的日期，所以我们将使用当前时间来解决这个问题。我们可以通过调用 <code>datetime()</code> 函数来获取当前时间。</p>\n<p>我们更新后的查询如下所示：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (article:Article)\nWHERE datetime() + article.readingTime &lt;= datetime() + duration(&quot;PT3M&quot;)\nRETURN article.title AS title,\n       article.created AS created,\n       article.datePublished AS datePublished,\n       article.readingTime AS readingTime\n</code></pre><p>表 7. 结果</p>\n<table>\n<thead>\n<tr>\n<th>title</th>\n<th>created</th>\n<th>datePublished</th>\n<th>readingTime</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>“Cypher Basics I”</td>\n<td>“01 June 2019 18:40”</td>\n<td>“01 June 2019”</td>\n<td>“02:15”</td>\n</tr>\n<tr>\n<td>“Cypher Basics II”</td>\n<td>“02 June 2019 10:23”</td>\n<td>“02 June 2019”</td>\n<td>“02:30”</td>\n</tr>\n</tbody>\n</table>\n<h2>资源</h2>\n<p>本节介绍了如何使用 APOC 库更有效地处理时间类型。以下是有关在 Neo4j 中使用时间类型的更多信息的资源：</p>\n<ul>\n<li>Cypher 中的时间（日期/时间）值</li>\n<li>APOC 库</li>\n<li>日期和时间转换</li>\n<li>时间函数</li>\n<li>开发人员博客：Cypher 侦探：处理日期，第 1 部分</li>\n</ul>\n</div>","title":"Neo4j官方教程：第15节，日期、日期时间和持续时间","last_reply_at":"2025-04-14T08:16:58.841Z","good":true,"top":false,"reply_count":0,"visit_count":2667,"create_at":"2025-04-14T08:16:58.841Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67fcc2eba755994623e85dc5","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/schema/\">https://neo4j.com/docs/getting-started/cypher-intro/schema/</a></p>\n<h1>定义模式</h1>\n<h2>示例图</h2>\n<p>首先创建一些数据以用于我们的示例：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (forrestGump:Movie {title: &#x27;Forrest Gump&#x27;, released: 1994})\nCREATE (robert:Person:Director {name: &#x27;Robert Zemeckis&#x27;, born: 1951})\nCREATE (tom:Person:Actor {name: &#x27;Tom Hanks&#x27;, born: 1956})\nCREATE (tom)-[:ACTED_IN {roles: [&#x27;Forrest&#x27;]}]-&gt;(forrestGump)\nCREATE (robert)-[:DIRECTED]-&gt;(forrestGump)\n</code></pre><p>这是生成的图：</p>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-schema-data-arr.svg\" alt=\"image\">\n(插入图表链接)</p>\n<h2>使用索引</h2>\n<p>在图数据库中使用索引的主要原因是找到图遍历的起点。一旦找到该起点，遍历就会依赖于图内结构来实现高性能。</p>\n<ul>\n<li>可以随时添加索引。</li>\n<li>如果数据库中存在现有数据，则索引联机需要一些时间。</li>\n</ul>\n<p>以下查询创建一个索引，以加快在数据库中按名称查找演员的速度：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE INDEX example_index_1 FOR (a:Actor) ON (a.name)\n</code></pre><p>在大多数情况下，在查询数据时无需指定索引，因为将自动使用适当的索引。</p>\n<p>可以使用索引提示在特定查询中指定要使用的索引。这是查询调优的几个选项之一，在 Cypher® 手册 → 查询调优 中有详细描述。</p>\n<p>例如，以下查询将自动使用 example_index_1：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (actor:Actor {name: &#x27;Tom Hanks&#x27;})\nRETURN actor\n</code></pre><p>复合索引是针对具有特定标签的所有节点的多个属性的索引。例如，以下语句将创建一个复合索引，该索引针对所有带有 <code>Actor</code> 标签并且同时具有 <code>name</code> 和 <code>born</code> 属性的节点。请注意，由于带有 <code>Actor</code> 标签且名称为“Keanu Reeves”的节点没有 <code>born</code> 属性。因此，该节点不会添加到索引中。</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE INDEX example_index_2 FOR (a:Actor) ON (a.name, a.born)\n</code></pre><p>您可以使用 <code>SHOW INDEXES</code> 查询数据库，以找出定义了哪些索引。</p>\n<pre class=\"prettyprint language-cypher\"><code>SHOW INDEXES YIELD name, labelsOrTypes, properties, type\n</code></pre><pre class=\"prettyprint\"><code>Rows: 2\n\n+----------------------------------------------------------------+\n| name              | labelsOrTypes | properties       | type    |\n+----------------------------------------------------------------+\n| &#x27;example_index_1&#x27; | [&#x27;Actor&#x27;]     | [&#x27;name&#x27;]         | &#x27;BTREE&#x27; |\n| &#x27;example_index_2&#x27; | [&#x27;Actor&#x27;]     | [&#x27;name&#x27;, &#x27;born&#x27;] | &#x27;BTREE&#x27; |\n+----------------------------------------------------------------+\n</code></pre><p>在 Cypher 手册 → 索引 中了解有关索引的更多信息。</p>\n<h2>使用约束</h2>\n<p>约束用于确保数据符合域的规则。例如：</p>\n<p>“如果一个节点具有 <code>Actor</code> 标签和 <code>name</code> 属性，则 <code>name</code> 的值在所有具有 <code>Actor</code> 标签的节点中必须是唯一的”。</p>\n<h3>示例 1. 唯一性约束</h3>\n<p>此示例显示了如何为具有 <code>Movie</code> 标签和 <code>title</code> 属性的节点创建约束。该约束指定 <code>title</code> 属性必须是唯一的。</p>\n<p>添加唯一性约束将隐式地在该属性上添加索引。如果删除约束，但仍然需要索引，则必须显式创建索引。</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE CONSTRAINT constraint_example_1 FOR (movie:Movie) REQUIRE movie.title IS UNIQUE\n</code></pre><p>Neo4j 4.4 中更改了语法，旧语法是：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE CONSTRAINT constraint_example_1 ON (movie:Movie) ASSERT movie.title IS UNIQUE Deprecated\n</code></pre><p>可以将约束添加到数据库中已存在数据的数据库。这要求现有数据符合正在添加的约束。</p>\n<p>您可以使用 <code>SHOW CONSTRAINTS</code> Cypher 语法查询数据库以找出定义了哪些约束。</p>\n<h3>示例 2. 约束查询</h3>\n<p>此示例显示了一个 Cypher 查询，该查询返回为数据库定义的约束。</p>\n<pre class=\"prettyprint language-cypher\"><code>SHOW CONSTRAINTS YIELD id, name, type, entityType, labelsOrTypes, properties, ownedIndexId\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+-----------------------------------------------------------------------------------------------------+\n| id | name                   | type         | entityType | labelsOrTypes | properties | ownedIndexId |\n+-----------------------------------------------------------------------------------------------------+\n| 4  | &#x27;constraint_example_1&#x27; | &#x27;UNIQUENESS&#x27; | &#x27;NODE&#x27;     | [&#x27;Movie&#x27;]     | [&#x27;title&#x27;]  | 3            |\n+-----------------------------------------------------------------------------------------------------+\n</code></pre><p>上述约束适用于所有版本的 Neo4j。其他约束可用于 Neo4j 企业版。</p>\n<p>在 Cypher 手册 → 约束 中了解有关约束的更多信息。</p>\n<p>Similar code found with 2 license types</p>\n</div>","title":"Neo4j官方教程：第14节，定义模式","last_reply_at":"2025-04-14T08:10:19.597Z","good":true,"top":false,"reply_count":0,"visit_count":2453,"create_at":"2025-04-14T08:10:19.597Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67fcc245a755994623e85dc4","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/subqueries/\">https://neo4j.com/docs/getting-started/cypher-intro/subqueries/</a></p>\n<h1>Cypher 中的子查询</h1>\n<h2>回顾我们的示例图</h2>\n<p>我们所有的代码示例将继续使用我们之前使用过的其中一个图示例，但包括更多数据以用于此页面上的查询。下图是新图，一个由人员、他们工作的公司以及他们喜欢的技术组成的网络。</p>\n<p>我们添加了一个 <code>Person</code> 节点（蓝色），该节点 <code>WORKS_FOR</code> 一个 <code>Company</code> 节点（红色）并且 <code>LIKES</code> 一个 <code>Technology</code> 节点（绿色）：Ryan 为 Company Z 工作并且喜欢 Python。您可以在图的右侧找到此数据。</p>\n<p>回顾一下，每个人也可能与其他人有多个 <code>IS_FRIENDS_WITH</code> 关系。</p>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/people-technologies-graph-arr1.svg\" alt=\"image\"></p>\n<p>图 1. 人员、他们工作的公司以及他们喜欢的技术的网络</p>\n<p>您可以使用以下 Cypher® 查询创建此数据集：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (diana:Person {name: &quot;Diana&quot;})-[:LIKES]-&gt;(query:Technology {type: &quot;Query Languages&quot;})\nCREATE (melissa:Person {name: &quot;Melissa&quot;, twitter: &quot;@melissa&quot;})-[:LIKES]-&gt;(query)\nCREATE (dan:Person {name: &quot;Dan&quot;, twitter: &quot;@dan&quot;, yearsExperience: 6})-[:LIKES]-&gt;(etl:Technology {type: &quot;Data ETL&quot;})&lt;-[:LIKES]-(melissa)\nCREATE (xyz:Company {name: &quot;XYZ&quot;})&lt;-[:WORKS_FOR]-(sally:Person {name: &quot;Sally&quot;, yearsExperience: 4})-[:LIKES]-&gt;(integrations:Technology {type: &quot;Integrations&quot;})&lt;-[:LIKES]-(dan)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(john:Person {name: &quot;John&quot;, yearsExperience: 5, birthdate: &quot;1985-04-04&quot;})-[:LIKES]-&gt;(java:Technology {type: &quot;Java&quot;})\nCREATE (john)&lt;-[:IS_FRIENDS_WITH]-(jennifer:Person {name: &quot;Jennifer&quot;, twitter: &quot;@jennifer&quot;, yearsExperience: 5, birthdate: &quot;1988-01-01&quot;})-[:LIKES]-&gt;(java)\nCREATE (john)-[:WORKS_FOR]-&gt;(xyz)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(melissa)\nCREATE (joe:Person {name: &quot;Joe&quot;, birthdate: &quot;1988-08-08&quot;})-[:LIKES]-&gt;(query)\nCREATE (mark:Person {name: &quot;Mark&quot;, twitter: &quot;@mark&quot;})\nCREATE (ann:Person {name: &quot;Ann&quot;})\nCREATE (x:Company {name: &quot;Company X&quot;})&lt;-[:WORKS_FOR]-(diana)&lt;-[:IS_FRIENDS_WITH]-(joe)-[:IS_FRIENDS_WITH]-&gt;(mark)-[:LIKES]-&gt;(graphs:Technology {type: &quot;Graphs&quot;})&lt;-[:LIKES]-(jennifer)-[:WORKS_FOR]-&gt;(:Company {name: &quot;Neo4j&quot;})\nCREATE (ann)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(mark)\nCREATE (john)-[:LIKES]-&gt;(:Technology {type: &quot;Application Development&quot;})&lt;-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]-&gt;(dan)-[:WORKS_FOR]-&gt;(abc:Company {name: &quot;ABC&quot;})\nCREATE (ann)-[:WORKS_FOR]-&gt;(abc)\nCREATE (a:Company {name: &quot;Company A&quot;})&lt;-[:WORKS_FOR]-(melissa)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(diana)\nCREATE (:Technology {type: &quot;Python&quot;})&lt;-[:LIKES]-(:Person {name: &quot;Ryan&quot;})-[:WORKS_FOR]-&gt;(:Company {name: &quot;Company Z&quot;})\n</code></pre><h2>子查询简介</h2>\n<p>子查询是在 Neo4j 4.0 中引入的。</p>\n<p>有关如何使用它们的详细信息，请转到 Cypher 手册 → 子查询。</p>\n<p>以下类型的子查询在 Neo4j 中是可能的：</p>\n<ul>\n<li><code>EXISTS</code> 子查询</li>\n<li><code>COUNT</code> 子查询</li>\n<li><code>CALL {…​}</code> 子查询子句</li>\n<li><code>CALL {…​} IN TRANSACTIONS</code> 子查询子句</li>\n<li><code>COLLECT</code> 子查询（在 5.6 中引入）</li>\n</ul>\n<p><code>EXISTS</code>、<code>COUNT</code> 和 <code>CALL {…​}</code> 子查询在本节中介绍。</p>\n<p>要了解有关使用 <code>CALL {…​} IN TRANSACTIONS</code> 的更多信息，请参阅以下教程中的代码示例，了解如何将 CSV 数据导入到 Neo4j 数据库中：</p>\n<ul>\n<li>教程：导入数据</li>\n<li>将 CSV 数据导入到 Neo4j</li>\n</ul>\n<p><code>COLLECT</code> 子查询是在 Neo4j 5.6 中引入的。这是一种新型的子查询，用于将子查询的结果收集到列表中，以便可以执行进一步的操作，如 <code>DISTINCT</code>、<code>ORDER BY</code>、<code>LIMIT</code> 和 <code>SKIP</code>。<code>COLLECT</code> 子查询与 <code>COUNT</code> 和 <code>EXISTS</code> 子查询的不同之处在于，最终的 <code>RETURN</code> 子句是强制性的。<code>COLLECT</code> 子查询中的 <code>RETURN</code> 子句必须只返回一列。</p>\n<h2>Cypher 子查询</h2>\n<p>子查询是在其自身范围内执行的一组 Cypher 语句。子查询通常从外部封闭查询中调用。</p>\n<p>以下是关于子查询的一些重要事项：</p>\n<ul>\n<li>子查询返回 <code>RETURN</code> 子句中变量引用的值。</li>\n<li>子查询不能返回与封闭查询中使用的变量同名的变量。</li>\n<li>您必须显式地将变量从封闭查询传递到子查询。</li>\n<li>子查询用大括号 (<code>{}</code>) 划定。</li>\n</ul>\n<p>在获取正确的结果一章的过滤模式部分中，您学习了如何基于模式进行过滤。例如，您可以编写以下查询来查找为 Neo4j 工作的人的朋友：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[r:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWHERE exists((p)-[:WORKS_FOR]-&gt;(:Company {name: &#x27;Neo4j&#x27;}))\nRETURN p, r, friend\n</code></pre><p>如果您在 Neo4j 浏览器中运行此查询，将返回以下图：</p>\n<p><img src=\"https://neo4j.com/docs/getting-started/_images/friends-of-neo4j.png\" alt=\"image\"></p>\n<p>图 2. 图格式的输出</p>\n<p>Cypher 子查询支持更强大的模式过滤。您可以不使用 <code>WHERE</code> 子句中的 <code>exists</code> 函数，而是使用 <code>EXISTS</code> 子查询。您可以使用以下查询重现前面的示例：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[r:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWHERE EXISTS {\n  MATCH (p)-[:WORKS_FOR]-&gt;(:Company {name: &#x27;Neo4j&#x27;})\n}\nRETURN p, r, friend\n</code></pre><p>您将获得相同的结果，这很好，但到目前为止，您所实现的只是用更多的代码做同样的事情！</p>\n<p>接下来，让我们编写一个子查询，该子查询的过滤能力比单独使用 <code>WHERE</code> 子句或 <code>exists</code> 函数所能实现的更强大。</p>\n<p>假设：</p>\n<ul>\n<li>您想找到为名称以“Company”开头的公司工作的人，并且他们喜欢至少一项被三个或更多人喜欢的技术。</li>\n<li>您不感兴趣知道这些技术是什么。</li>\n</ul>\n<p>您可以尝试使用以下查询来回答这个问题：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (person:Person)-[:WORKS_FOR]-&gt;(company)\nWHERE company.name STARTS WITH &quot;Company&quot;\nAND (person)-[:LIKES]-&gt;(t:Technology)\nAND COUNT { (t)&lt;-[:LIKES]-() } &gt;= 3\nRETURN person.name as person, company.name AS company;\n</code></pre><p>如果您运行此查询，您将看到以下输出：</p>\n<pre class=\"prettyprint\"><code>Variable &#96;t&#96; not defined (line 4, column 25 (offset: 112))\n&quot;AND (person)-[:LIKES]-&gt;(t:Technology)&quot;\n                         ^\n</code></pre><p>您可以找到喜欢某项技术的人，但您无法检查是否至少有其他三个人也喜欢该技术，因为变量 <code>t</code> 不在 <code>WHERE</code> 子句的范围内。让我们将两个 <code>AND</code> 语句移动到 <code>EXISTS</code> 子查询块中，从而得到以下查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (person:Person)-[:WORKS_FOR]-&gt;(company)\nWHERE company.name STARTS WITH &quot;Company&quot;\nAND EXISTS {\n  MATCH (person)-[:LIKES]-&gt;(t:Technology)\n  WHERE COUNT { (t)&lt;-[:LIKES]-() } &gt;= 3\n}\nRETURN person.name as person, company.name AS company;\n</code></pre><p>现在您可以成功运行查询，该查询返回以下结果：</p>\n<pre class=\"prettyprint\"><code>person\tcompany\n&quot;Melissa&quot;\t&quot;CompanyA&quot;\n&quot;Diana&quot;\t&quot;CompanyX&quot;\n</code></pre><p>如果您回忆起本指南开头的图可视化，Ryan 是唯一另一个为名称以“Company”开头的公司工作的人。他已在此查询中被过滤掉，因为他喜欢的唯一技术是 Python，并且没有其他三个人喜欢 Python。</p>\n<h2>结果返回子查询</h2>\n<p>到目前为止，您已经学习了如何使用子查询来过滤掉结果，但这并没有完全显示它们的强大功能。您还可以使用子查询来返回结果。</p>\n<p>假设您要编写一个查询，查找喜欢 Java 或有多个朋友的人。除此之外，您希望按出生日期降序对结果进行排序。这可以使用 <code>UNION</code> 子句和 <code>COUNT</code> 子查询部分实现：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:LIKES]-&gt;(:Technology {type: &quot;Java&quot;})\nRETURN p.name AS person, p.birthdate AS dob\nORDER BY dob DESC\n\nUNION\n\nMATCH (p:Person)\nWHERE COUNT { (p)-[:IS_FRIENDS_WITH]-&gt;() } &gt; 1\nRETURN p.name AS person, p.birthdate AS dob\nORDER BY dob DESC;\n</code></pre><p>如果您运行该查询，您将看到以下输出：</p>\n<pre class=\"prettyprint\"><code>person\tdob\n&quot;Jennifer&quot;\t&quot;1988-01-01&quot;\n&quot;John&quot;\t&quot;1985-04-04&quot;\n&quot;Joe&quot;\t&quot;1988-08-08&quot;\n</code></pre><p>您得到了正确的人。但是 <code>UNION</code> 方法只允许我们按 <code>UNION</code> 子句对结果进行排序，而不是对所有行进行排序。</p>\n<p>您可以尝试另一种方法，即分别执行每个子查询，并使用 <code>collect()</code> 函数从每个部分收集人员。有些人喜欢 Java 并且有多个朋友，因此您需要在 <code>RETURN</code> 子句中使用 <code>DISTINCT</code> 运算符来删除重复项：</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F; Find people who like Java\nMATCH (p:Person)-[:LIKES]-&gt;(:Technology {type: &quot;Java&quot;})\nWITH collect(p) AS peopleWhoLikeJava\n\n&#x2F;&#x2F; Find people with more than one friend\nMATCH (p:Person)\nWHERE COUNT { (p)-[:IS_FRIENDS_WITH]-&gt;() } &gt; 1\nWITH collect(p) AS popularPeople, peopleWhoLikeJava\nWITH popularPeople + peopleWhoLikeJava AS people\n\n&#x2F;&#x2F; Unpack the collection of people and order by birthdate\nUNWIND people AS p\nRETURN DISTINCT p.name AS person, p.birthdate AS dob\nORDER BY dob DESC\n</code></pre><p>如果您运行该查询，您将获得以下输出：</p>\n<pre class=\"prettyprint\"><code>person\tdob\n&quot;Joe&quot;\t&quot;1988-08-08&quot;\n&quot;Jennifer&quot;\t&quot;1988-01-01&quot;\n&quot;John&quot;\t&quot;1985-04-04&quot;\n</code></pre><p>这种方法有效，但更难编写，因为您必须不断地将查询的各个部分传递到它的下一部分。</p>\n<p><code>CALL {…​}</code> 子句为您提供了两全其美的优势：</p>\n<ul>\n<li>您可以使用 <code>UNION</code> 方法来运行各个查询并删除重复项。</li>\n<li>您可以在之后对结果进行排序。</li>\n</ul>\n<p>我们使用 <code>CALL {…​}</code> 子句的查询如下所示：</p>\n<pre class=\"prettyprint language-cypher\"><code>CALL {\n\tMATCH (p:Person)-[:LIKES]-&gt;(:Technology {type: &quot;Java&quot;})\n\tRETURN p\n\n\tUNION\n\n\tMATCH (p:Person)\n\tWHERE COUNT { (p)-[:IS_FRIENDS_WITH]-&gt;() } &gt; 1\n\tRETURN p\n}\nRETURN p.name AS person, p.birthdate AS dob\nORDER BY dob DESC;\n</code></pre><p>如果您运行该查询，您将获得以下输出：</p>\n<pre class=\"prettyprint\"><code>person\tdob\n&quot;Joe&quot;\t&quot;1988-08-08&quot;\n&quot;Jennifer&quot;\t&quot;1988-01-01&quot;\n&quot;John&quot;\t&quot;1985-04-04&quot;\n</code></pre><p>您可以进一步扩展查询以返回这些人喜欢的技术以及他们拥有的朋友。以下查询显示了如何执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>CALL {\n\tMATCH (p:Person)-[:LIKES]-&gt;(:Technology {type: &quot;Java&quot;})\n\tRETURN p\n\n\tUNION\n\n\tMATCH (p:Person)\n\tWHERE COUNT { (p)-[:IS_FRIENDS_WITH]-&gt;() } &gt; 1\n\tRETURN p\n}\nWITH p,\n     [(p)-[:LIKES]-&gt;(t) | t.type] AS technologies,\n     [(p)-[:IS_FRIENDS_WITH]-&gt;(f) | f.name] AS friends\n\nRETURN p.name AS person, p.birthdate AS dob, technologies, friends\nORDER BY dob DESC;\n</code></pre><pre class=\"prettyprint\"><code>person\tdob\ttechnologies\tfriends\n&quot;Joe&quot;\t&quot;1988-08-08&quot;\t[&quot;Query Languages&quot;]\t[&quot;Mark&quot;, &quot;Diana&quot;]\n&quot;Jennifer&quot;\t&quot;1988-01-01&quot;\t[&quot;Graphs&quot;, &quot;Java&quot;]\t[&quot;Sally&quot;, &quot;Mark&quot;, &quot;John&quot;, &quot;Ann&quot;, &quot;Melissa&quot;]\n&quot;John&quot;\t&quot;1985-04-04&quot;\t[&quot;Java&quot;, &quot;Application Development&quot;]\t[&quot;Sally&quot;]\n</code></pre><p>您还可以将聚合函数应用于子查询的结果。以下查询返回喜欢 Java 或有多个朋友的人中最年轻和最年长的人。</p>\n<pre class=\"prettyprint language-cypher\"><code>CALL {\n\tMATCH (p:Person)-[:LIKES]-&gt;(:Technology {type: &quot;Java&quot;})\n\tRETURN p\n\n\tUNION\n\n\tMATCH (p:Person)\n\tWHERE COUNT { (p)-[:IS_FRIENDS_WITH]-&gt;() } &gt; 1\n\tRETURN p\n}\nRETURN min(p.birthdate) AS oldest, max(p.birthdate) AS youngest\n</code></pre><pre class=\"prettyprint\"><code>oldest\tyoungest\n&quot;1985-04-04&quot;\t&quot;1988-08-08&quot;\n</code></pre><h2>总结</h2>\n<p>您已经了解了如何使用 <code>EXISTS {}</code> 子查询编写复杂的过滤模式，以及如何使用 <code>CALL {}</code> 子句执行返回结果的子查询。</p>\n<p>Similar code found with 1 license type</p>\n</div>","title":"Neo4j官方教程：第13节， Cypher 中的子查询","last_reply_at":"2025-04-14T08:07:33.738Z","good":true,"top":false,"reply_count":0,"visit_count":2647,"create_at":"2025-04-14T08:07:33.738Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67f869905885e744204e1839","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/large-statements/\">https://neo4j.com/docs/getting-started/cypher-intro/large-statements/</a></p>\n<h1>编写大型语句</h1>\n<h2>示例图</h2>\n<p>我们继续使用与之前相同的示例数据：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (matrix:Movie {title: &#x27;The Matrix&#x27;, released: 1997})\nCREATE (cloudAtlas:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012})\nCREATE (forrestGump:Movie {title: &#x27;Forrest Gump&#x27;, released: 1994})\nCREATE (keanu:Person {name: &#x27;Keanu Reeves&#x27;, born: 1964})\nCREATE (robert:Person {name: &#x27;Robert Zemeckis&#x27;, born: 1951})\nCREATE (tom:Person {name: &#x27;Tom Hanks&#x27;, born: 1956})\nCREATE (tom)-[:ACTED_IN {roles: [&#x27;Forrest&#x27;]}]-&gt;(forrestGump)\nCREATE (tom)-[:ACTED_IN {roles: [&#x27;Zachry&#x27;]}]-&gt;(cloudAtlas)\nCREATE (robert)-[:DIRECTED]-&gt;(forrestGump)\n</code></pre><p>这是生成的图：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-results01-arr.svg\" alt=\"image\">\n(插入图表链接)</p>\n<p>图 1. 电影图</p>\n<h2>UNION</h2>\n<p>如果要组合具有相同结果结构的两个语句的结果，可以使用 <code>UNION [ALL]</code>。</p>\n<p>例如，以下查询列出了演员和导演：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (actor:Person)-[r:ACTED_IN]-&gt;(movie:Movie)\nRETURN actor.name AS name, type(r) AS type, movie.title AS title\nUNION\nMATCH (director:Person)-[r:DIRECTED]-&gt;(movie:Movie)\nRETURN director.name AS name, type(r) AS type, movie.title AS title\n</code></pre><pre class=\"prettyprint\"><code>Rows: 3\n\n+-------------------------------------------------+\n| name              | type       | title          |\n+-------------------------------------------------+\n| &#x27;Tom Hanks&#x27;       | &#x27;ACTED_IN&#x27; | &#x27;Cloud Atlas&#x27;  |\n| &#x27;Tom Hanks&#x27;       | &#x27;ACTED_IN&#x27; | &#x27;Forrest Gump&#x27; |\n| &#x27;Robert Zemeckis&#x27; | &#x27;DIRECTED&#x27; | &#x27;Forrest Gump&#x27; |\n+-------------------------------------------------+\n</code></pre><p>请注意，返回的列必须在所有子句中以相同的方式设置别名。</p>\n<p>上面的查询等效于这个更紧凑的查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (actor:Person)-[r:ACTED_IN|DIRECTED]-&gt;(movie:Movie)\nRETURN actor.name AS name, type(r) AS type, movie.title AS title\n</code></pre><h2>WITH</h2>\n<p>在 Cypher® 中，您可以将语句片段链接在一起，类似于在数据流管道中完成的方式。每个片段都处理前一个片段的输出，并且其结果可以馈送到下一个片段中。只有在 <code>WITH</code> 子句中声明的列才在后续查询部分中可用。</p>\n<p><code>WITH</code> 子句用于组合各个部分并声明数据从一个部分流向另一个部分。<code>WITH</code> 类似于 <code>RETURN</code> 子句。不同之处在于 <code>WITH</code> 子句不会完成查询，而是为下一部分准备输入。表达式、聚合、排序和分页可以以与 <code>RETURN</code> 子句相同的方式使用。唯一的区别是所有列都必须设置别名。</p>\n<p>在以下示例中，收集某人出演的电影，然后过滤掉仅出现在一部电影中的电影。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (person:Person)-[:ACTED_IN]-&gt;(m:Movie)\nWITH person, count(*) AS appearances, collect(m.title) AS movies\nWHERE appearances &gt; 1\nRETURN person.name, appearances, movies\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+-------------------------------------------------------------+\n| person.name | appearances | movies                          |\n+-------------------------------------------------------------+\n| &#x27;Tom Hanks&#x27; | 2           | [&#x27;Cloud Atlas&#x27;, &#x27;Forrest Gump&#x27;] |\n+-------------------------------------------------------------+\n</code></pre><p>使用 <code>WITH</code> 子句，您可以将值从查询的一部分传递到另一部分。这允许您在查询中执行一些中间计算或操作以供以后使用。</p>\n<p>以下数据集用于演示下面的示例：\n<img src=\"https://neo4j.com/docs/getting-started/_images/people-technologies-graph-arr.svg\" alt=\"image\">\n(插入图表链接)</p>\n<p>图 2. 图：人员、他们喜欢的技术以及他们工作的公司</p>\n<p>要重现该图，请运行 Cypher 代码：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (diana:Person {name: &quot;Diana&quot;})\nCREATE (melissa:Person {name: &quot;Melissa&quot;, twitter: &quot;@melissa&quot;})\nCREATE (dan:Person {name: &quot;Dan&quot;, twitter: &quot;@dan&quot;, yearsExperience: 6})\nCREATE (sally:Person {name: &quot;Sally&quot;, yearsExperience: 4})\nCREATE (john:Person {name: &quot;John&quot;, twitter: &quot;@jennifer&quot;, yearsExperience: 5})\nCREATE (joe:Person {name: &quot;Joe&quot;})\nCREATE (mark:Person {name: &quot;Mark&quot;, twitter: &quot;@mark&quot;})\nCREATE (ann:Person {name: &quot;Ann&quot;})\nCREATE (xyz:Company {name: &quot;XYZ&quot;})\nCREATE (x:Company {name: &quot;Company X&quot;})\nCREATE (a:Company {name: &quot;Company A&quot;})\nCREATE (Neo4j:Company {name: &quot;Neo4j&quot;})\nCREATE (abc:Company {name: &quot;ABC&quot;})\nCREATE (query:Technology {type: &quot;Query Languages&quot;})\nCREATE (etl:Technology {type: &quot;Data ETL&quot;})\nCREATE (integrations:Technology {type: &quot;Integrations&quot;})\nCREATE (graphs:Technology {type: &quot;Graphs&quot;})\nCREATE (dev:Technology {type: &quot;Application Development&quot;})\nCREATE (java:Technology {type: &quot;Java&quot;})\nCREATE (diana)-[:LIKES]-&gt;(query)\nCREATE (melissa)-[:LIKES]-&gt;(query)\nCREATE (dan)-[:LIKES]-&gt;(etl)&lt;-[:LIKES]-(melissa)\nCREATE (xyz)&lt;-[:WORKS_FOR]-(sally)-[:LIKES]-&gt;(integrations)&lt;-[:LIKES]-(dan)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(john)-[:LIKES]-&gt;(java)\nCREATE (john)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:LIKES]-&gt;(java)\nCREATE (john)-[:WORKS_FOR]-&gt;(xyz)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(melissa)\nCREATE (joe)-[:LIKES]-&gt;(query)\nCREATE (x)&lt;-[:WORKS_FOR]-(diana)&lt;-[:IS_FRIENDS_WITH]-(joe)-[:IS_FRIENDS_WITH]-&gt;(mark)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(jennifer)-[:WORKS_FOR]-&gt;(Neo4j)\nCREATE (ann)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(mark)\nCREATE (john)-[:LIKES]-&gt;(dev)&lt;-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]-&gt;(dan)-[:WORKS_FOR]-&gt;(abc)\nCREATE (ann)-[:WORKS_FOR]-&gt;(abc)\nCREATE (a)&lt;-[:WORKS_FOR]-(melissa)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(diana)\n</code></pre><p>您必须在 <code>WITH</code> 子句中指定您以后要使用的变量。只有这些变量会传递到查询的下一部分。有多种方法可以使用此功能（例如，计数、收集、过滤、限制结果）。</p>\n<p>有关如何使用 <code>WITH</code> 的更多信息，请参阅 Cypher 手册部分。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: find and list the technologies people like\nMATCH (a:Person)-[r:LIKES]-(t:Technology)\nWITH a.name AS name, collect(t.type) AS technologies\nRETURN name, technologies;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 9\n\n+----------------------------------------------------------+\n| name        | technologies                               |\n+----------------------------------------------------------+\n| &#x27;Sally&#x27;     | [&#x27;Integrations&#x27;]                           |\n| &#x27;Dan&#x27;       | [&#x27;Data ETL&#x27;, &#x27;Integrations&#x27;]               |\n| &#x27;John&#x27;      | [&#x27;Java&#x27;, &#x27;Application Development&#x27;]        |\n| &#x27;Diana&#x27;     | [&#x27;Query Languages&#x27;, &#x27;Graphs&#x27;]              |\n| &#x27;Jennifer&#x27;  | [&#x27;Java&#x27;, &#x27;Graphs&#x27;]                         |\n| &#x27;Ann&#x27;       | [&#x27;Application Development&#x27;]                |\n| &#x27;Mark&#x27;      | [&#x27;Graphs&#x27;]                                 |\n| &#x27;Joe&#x27;       | [&#x27;Query Languages&#x27;]                        |\n| &#x27;Melissa&#x27;   | [&#x27;Query Languages&#x27;, &#x27;Data ETL&#x27;, &#x27;Graphs&#x27;]  |\n+----------------------------------------------------------+\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query2: find number of friends who have other friends\nMATCH (p:Person)-[:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWITH p, collect(friend.name) AS friendsList, count{(friend)-[:IS_FRIENDS_WITH]-(:Person)} AS numberOfFoFs\nWHERE numberOfFoFs &gt; 1\nRETURN p.name, friendsList, numberOfFoFs;\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 3\n\n+---------------------------------------------------+-----------------+\n| p.name        | friendList                        | numberOfFoFs    |\n+---------------------------------------------------+-----------------+\n| &#x27;Joe&#x27;         | [&#x27;Mark&#x27;]                          | 2               |\n| &#x27;Jennifer&#x27;    | [&#x27;Sally&#x27;, &#x27;John&#x27;, &#x27;Ann&#x27;, &#x27;Mark&#x27;]  | 2               |\n| &#x27;John&#x27;        | [&#x27;Sally&#x27;]                         | 2               |\n+---------------------------------------------------+-----------------+\n</code></pre><p>在第一个查询中，传递了人员姓名和收集的技术类型列表。因此，只有这些项目可以在 <code>RETURN</code> 子句中引用。关系 ® 和人员出生日期都不能使用，因为这些值没有传递。</p>\n<p>在第二个查询中，只能引用 p 及其任何属性（姓名、出生日期、工作年限、Twitter）、朋友的集合（作为一个整体，而不是每个值）以及朋友的朋友的数量。由于这些值已在 <code>WITH</code> 子句中传递，因此可以在 <code>WHERE</code> 或 <code>RETURN</code> 子句中使用它们。</p>\n<p><code>WITH</code> 要求传递的所有值都具有变量（如果它们还没有变量）。<code>Person</code> 节点在 <code>MATCH</code> 子句中被赋予变量 §，因此不需要在那里分配变量。</p>\n<p><code>WITH</code> 对于在查询之前设置参数也非常有用。在导入数据时，通常对参数键、URL 字符串和其他查询变量很有用。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Find people with 2-6 years of experience\nWITH 2 AS experienceMin, 6 AS experienceMax\nMATCH (p:Person)\nWHERE experienceMin &lt;= p.yearsExperience &lt;= experienceMax\nRETURN p\n</code></pre></div>","title":"Neo4j官方教程：第12节，编写大型语句","last_reply_at":"2025-04-11T01:00:00.228Z","good":true,"top":false,"reply_count":0,"visit_count":2464,"create_at":"2025-04-11T01:00:00.228Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67f867115885e744204e1838","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自:<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/updating/\">https://neo4j.com/docs/getting-started/cypher-intro/updating/</a></p>\n<h1>更新数据</h1>\n<p>之前您学习了如何在 Cypher® 中表示节点、关系、标签、属性和模式。本节通过介绍如何使用 Cypher 更新和删除数据，在您的知识中添加另一个层次。</p>\n<p>虽然这些是标准的 CRUD（创建、读取、更新和删除）操作，但与在其他类型的数据库中相比，某些功能在图中有所不同。当我们进行时，您可能会认识到一些相似之处和不同之处。</p>\n<h2>使用 Cypher 更新数据</h2>\n<p>您可能已经在数据中有一个节点或关系，但您想修改其属性。您可以通过匹配要查找的模式并使用 <code>SET</code> 关键字来添加、删除或更新属性来执行此操作。</p>\n<p>我们继续使用以下数据集：\n<img src=\"https://neo4j.com/docs/getting-started/_images/people-technologies-graph-arr.svg\" alt=\"image\"></p>\n<p>图 1. 图：人员、他们工作的公司以及他们喜欢的技术</p>\n<p>要创建上述图，请运行 Cypher 查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (diana:Person {name: &quot;Diana&quot;})\nCREATE (melissa:Person {name: &quot;Melissa&quot;, twitter: &quot;@melissa&quot;})\nCREATE (dan:Person {name: &quot;Dan&quot;, twitter: &quot;@dan&quot;, yearsExperience: 6})\nCREATE (sally:Person {name: &quot;Sally&quot;, yearsExperience: 4})\nCREATE (john:Person {name: &quot;John&quot;, yearsExperience: 5})\nCREATE (jennifer:Person {name: &quot;Jennifer&quot;, twitter: &quot;@jennifer&quot;, yearsExperience: 5})\nCREATE (joe:Person {name: &quot;Joe&quot;})\nCREATE (mark:Person {name: &quot;Mark&quot;, twitter: &quot;@mark&quot;})\nCREATE (ann:Person {name: &quot;Ann&quot;})\nCREATE (xyz:Company {name: &quot;XYZ&quot;})\nCREATE (x:Company {name: &quot;Company X&quot;})\nCREATE (a:Company {name: &quot;Company A&quot;})\nCREATE (Neo4j:Company {name: &quot;Neo4j&quot;})\nCREATE (abc:Company {name: &quot;ABC&quot;})\nCREATE (query:Technology {type: &quot;Query Languages&quot;})\nCREATE (etl:Technology {type: &quot;Data ETL&quot;})\nCREATE (integrations:Technology {type: &quot;Integrations&quot;})\nCREATE (graphs:Technology {type: &quot;Graphs&quot;})\nCREATE (dev:Technology {type: &quot;Application Development&quot;})\nCREATE (java:Technology {type: &quot;Java&quot;})\nCREATE (diana)-[:LIKES]-&gt;(query)\nCREATE (melissa)-[:LIKES]-&gt;(query)\nCREATE (dan)-[:LIKES]-&gt;(etl)&lt;-[:LIKES]-(melissa)\nCREATE (xyz)&lt;-[:WORKS_FOR]-(sally)-[:LIKES]-&gt;(integrations)&lt;-[:LIKES]-(dan)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(john)-[:LIKES]-&gt;(java)\nCREATE (john)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:LIKES]-&gt;(java)\nCREATE (john)-[:WORKS_FOR]-&gt;(xyz)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(melissa)\nCREATE (joe)-[:LIKES]-&gt;(query)\nCREATE (x)&lt;-[:WORKS_FOR]-(diana)&lt;-[:IS_FRIENDS_WITH]-(joe)-[:IS_FRIENDS_WITH]-&gt;(mark)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(jennifer)-[:WORKS_FOR]-&gt;(Neo4j)\nCREATE (ann)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(mark)\nCREATE (john)-[:LIKES]-&gt;(dev)&lt;-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]-&gt;(dan)-[:WORKS_FOR]-&gt;(abc)\nCREATE (ann)-[:WORKS_FOR]-&gt;(abc)\nCREATE (a)&lt;-[:WORKS_FOR]-(melissa)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(diana)\n</code></pre><p>到目前为止，使用上面的示例数据集，您可以更新 Jennifer 的节点以添加她的出生日期。下一个 Cypher 语句显示了如何执行此操作。</p>\n<ul>\n<li>首先，您需要找到 Jennifer 的现有节点。</li>\n<li>接下来，使用 <code>SET</code> 创建新属性（使用语法 <code>variable.property</code>）并设置其值。</li>\n<li>最后，您可以返回 Jennifer 的节点以确保信息已正确更新。</li>\n</ul>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Jennifer&#x27;})\nSET p.birthdate = date(&#x27;1980-01-01&#x27;)\nRETURN p\n</code></pre><p>查询结果：</p>\n<pre class=\"prettyprint\"><code>Set Properties: 1\nRows: 1\n\n+------------------------------------------------------+\n| p                                                    |\n+------------------------------------------------------+\n|(Person: {birthdate: &#x27;1980-01-01&#x27;, name: &#x27;Jennifer&#x27;}) |\n+------------------------------------------------------+\n</code></pre><p>有关使用 <code>date()</code> 和其他时间函数的更多信息，请访问 Cypher 手册 → 时间函数。</p>\n<p>如果要更改 Jennifer 的出生日期，可以使用上面的同一查询再次找到 Jennifer 的节点，并在 <code>SET</code> 子句中放入不同的日期。</p>\n<p>您还可以使用 <code>Company</code> 节点更新 Jennifer 的 <code>WORKS_FOR</code> 关系，以包括她开始在那里工作的年份。为此，您可以使用与上面类似的语法来更新节点。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Person {name: &#x27;Jennifer&#x27;})-[rel:WORKS_FOR]-(:Company {name: &#x27;Neo4j&#x27;})\nSET rel.startYear = date({year: 2018})\nRETURN rel\n</code></pre><p>查询结果：</p>\n<pre class=\"prettyprint\"><code>Set Properties: 1\nRows: 1\n\n+-----------------------------------------+\n| rel                                     |\n+-----------------------------------------+\n| [:WORKS_FOR {startYear: &#x27;2018-01-01&#x27;}]  |\n+-----------------------------------------+\n</code></pre><p>如果要返回上述查询的图视图，可以将变量添加到节点 <code>p:Person</code> 和 <code>c:Company</code>，并将返回行写为 <code>RETURN p, rel, c</code>。</p>\n<h2>使用 Cypher 删除数据</h2>\n<p>要介绍的另一个操作是如何在 Cypher 中删除数据。对于此操作，Cypher 使用 <code>DELETE</code> 关键字删除节点和关系。它与其他语言（如 SQL）中删除数据非常相似，但有一个例外。</p>\n<p>由于 Neo4j 符合 ACID，因此如果节点仍具有关系，则无法删除该节点。如果可以这样做，那么您最终可能会得到指向空的关系和不完整的图。</p>\n<h3>删除关系</h3>\n<p>要删除关系，您需要找到要删除的关系的开始和结束节点，然后使用 <code>DELETE</code> 关键字，如下面的代码块所示。让我们继续删除 Jennifer 和 Mark 之间的 <code>IS_FRIENDS_WITH</code> 关系。我们稍后将在练习中重新添加此关系。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (j:Person {name: &#x27;Jennifer&#x27;})-[r:IS_FRIENDS_WITH]-&gt;(m:Person {name: &#x27;Mark&#x27;})\nDELETE r\n</code></pre><p>查询结果：</p>\n<pre class=\"prettyprint\"><code>+-----------------------------------------+\n| Deleted Relationships: 1                |\n| Rows: 0                                 |\n+-----------------------------------------+\n</code></pre><h3>删除节点</h3>\n<p>要删除没有任何关系的节点，您需要找到要删除的节点，然后使用 <code>DELETE</code> 关键字，就像您对上面的关系所做的那样。您可以暂时删除 Mark 的节点，稍后再将其恢复。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Person {name: &#x27;Mark&#x27;})\nDELETE m\n</code></pre><p>查询结果：</p>\n<pre class=\"prettyprint\"><code>+-----------------------------------------+\n| Deleted Nodes: 1                        |\n| Rows: 0                                 |\n+-----------------------------------------+\n</code></pre><p>如果您错误地创建了一个空节点并且需要删除它，您可以使用以下 Cypher 语句来执行此操作：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (n)\nWHERE id(n) = 5\nDETACH DELETE n\n</code></pre><p>此语句不仅删除节点，还删除它具有的所有关系。要运行该语句，您应该知道节点的内部 ID。</p>\n<h3>删除节点及其关系</h3>\n<p>您可以运行单个语句来删除节点及其关系，而不是运行最后两个查询来删除 <code>IS_FRIENDS_WITH</code> 关系和 Mark 的 <code>Person</code> 节点。如上所述，Neo4j 符合 ACID，因此不允许删除仍具有关系的节点。使用 <code>DETACH DELETE</code> 语法告诉 Cypher 删除节点具有的任何关系，并删除节点本身。</p>\n<p>该语句如下面的代码所示。首先，您在数据库中找到 Mark 的节点。然后，<code>DETACH DELETE</code> 行删除 Mark 节点具有的任何现有关系，然后再删除该节点。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Person {name: &#x27;Mark&#x27;})\nDETACH DELETE m\n</code></pre><h3>删除属性</h3>\n<p>您还可以删除属性，但您可以使用其他几种方法，而不是使用 <code>DELETE</code> 关键字。</p>\n<ul>\n<li>第一种选择是在属性上使用 <code>REMOVE</code>。这告诉 Neo4j 您要从节点中完全删除该属性，并且不再存储它。</li>\n<li>第二个选项是使用之前的 <code>SET</code> 关键字将属性值设置为 null。与其他数据库模型不同，Neo4j 不存储空值。相反，它只存储对您的数据有意义的属性和值。这意味着您可以在图中的各种节点和关系上具有不同类型和数量的属性。</li>\n</ul>\n<p>为了向您展示这两种选择，让我们看一下每种方法的代码。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;delete property using REMOVE keyword\nMATCH (n:Person {name: &#x27;Jennifer&#x27;})\nREMOVE n.birthdate\n\n&#x2F;&#x2F;delete property with SET to null value\nMATCH (n:Person {name: &#x27;Jennifer&#x27;})\nSET n.birthdate = null\n</code></pre><p>查询结果：</p>\n<pre class=\"prettyprint\"><code>+-----------------------------------------+\n| Set Properties: 1                       |\n| Rows: 0                                 |\n+-----------------------------------------+\n</code></pre><h2>使用 MERGE 避免重复数据</h2>\n<p>前面简要提到了 Cypher 中有一些方法可以避免创建重复数据。其中一种方法是使用 <code>MERGE</code> 关键字。<code>MERGE</code> 执行“选择或插入”操作，该操作首先检查数据库中是否存在数据。如果存在，则 Cypher 按原样返回它，或者对现有节点或关系进行您指定的任何更新。如果数据不存在，则 Cypher 将使用您指定的信息创建它。</p>\n<h3>在节点上使用 MERGE</h3>\n<p>首先，让我们通过使用下面的查询将 Mark 添加回我们的数据库来查看一个示例。您可以使用 <code>MERGE</code> 来确保 Cypher 检查数据库中是否存在 Mark 的现有节点。由于您在前面的示例中删除了 Mark 的节点，因此 Cypher 将找不到现有匹配项，并将使用设置为“Mark”的名称属性创建一个新节点。</p>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (mark:Person {name: &#x27;Mark&#x27;})\nRETURN mark\n</code></pre><p>查询结果：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher_graph_mergeFriend-arr.svg\" alt=\"image\">\n(插入图表链接)</p>\n<p>如果再次运行相同的语句，Cypher 这次将找到一个名称属性设置为 Mark 的现有节点，因此它将返回匹配的节点，而不会进行任何更改。</p>\n<h3>在关系上使用 MERGE</h3>\n<p>就像您使用 <code>MERGE</code> 在 Cypher 中查找或创建节点一样，您可以执行相同的操作来查找或创建关系。让我们重新创建我们在先前示例中拥有的 Mark 和 Jennifer 之间的 <code>IS_FRIENDS_WITH</code> 关系。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (j:Person {name: &#x27;Jennifer&#x27;})\nMATCH (m:Person {name: &#x27;Mark&#x27;})\nMERGE (j)-[r:IS_FRIENDS_WITH]-&gt;(m)\nRETURN j, r, m\n</code></pre><p>请注意，此处使用 <code>MATCH</code> 在使用 <code>MERGE</code> 查找或创建它们之间关系之前查找 Mark 的节点和 Jennifer 的节点。</p>\n<h3>为什么我们不使用单个语句？</h3>\n<p><code>MERGE</code> 查找您指定的整个模式，以查看是返回现有模式还是创建新模式。如果整个模式（节点、关系和任何指定的属性）不存在，则 Cypher 会创建它。</p>\n<p>Cypher 永远不会在模式中产生匹配和创建的部分混合。为避免匹配和创建的混合，您需要在对可能要创建的任何元素执行合并之前，首先匹配模式的任何现有元素，就像我们在上面的语句中所做的那样。\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher_graph_mergeFriendRel-arr.svg\" alt=\"image\">\n(插入图表链接)</p>\n<p>仅供参考，导致重复项的 Cypher 语句如下。由于此模式（Jennifer IS_FRIENDS_WITH Mark）在数据库中不存在，因此 Cypher 会创建一个全新的模式 - 两个节点以及它们之间的关系。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;this statement will create duplicate nodes for Mark and Jennifer\nMERGE (j:Person {name: &#x27;Jennifer&#x27;})-[r:IS_FRIENDS_WITH]-&gt;(m:Person {name: &#x27;Mark&#x27;})\nRETURN j, r, m\n</code></pre><h3>处理 MERGE 标准</h3>\n<p>也许您想使用 <code>MERGE</code> 来确保您不创建重复项，但是如果创建了模式，您想初始化某些属性，如果仅匹配了模式，则要更新其他属性。在这种情况下，您可以将 <code>ON CREATE</code> 或 <code>ON MATCH</code> 与 <code>SET</code> 关键字一起使用来处理这些情况。</p>\n<p>让我们看一个例子。</p>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (m:Person {name: &#x27;Mark&#x27;})-[r:IS_FRIENDS_WITH]-(j:Person {name:&#x27;Jennifer&#x27;})\n  ON CREATE SET r.since = date(&#x27;2018-03-01&#x27;)\n  ON MATCH SET r.updated = date()\nRETURN m, r, j\n</code></pre><p>资源</p>\n<ul>\n<li>Neo4j Cypher 手册：CREATE</li>\n<li>Neo4j Cypher 手册：SET</li>\n<li>Neo4j Cypher 手册：REMOVE</li>\n<li>Neo4j Cypher 手册：DELETE</li>\n<li>Neo4j Cypher 手册：MERGE</li>\n<li>Neo4j Cypher 手册：ON CREATE/ON MATCH</li>\n</ul>\n</div>","title":"Neo4j官方教程：第11节，更新数据","last_reply_at":"2025-04-11T00:49:21.036Z","good":true,"top":false,"reply_count":0,"visit_count":3150,"create_at":"2025-04-11T00:49:21.036Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67f5db4e455186f56d9f4135","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/results/\">https://neo4j.com/docs/getting-started/cypher-intro/results/</a></p>\n<h1>获取正确的结果</h1>\n<h2>示例图</h2>\n<p>在本节中，使用了两个示例数据集。第一个图基于电影数据库。以下代码块可帮助您创建用于探索 Cypher® 查询的数据：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (matrix:Movie {title: &#x27;The Matrix&#x27;, released: 1997})\nCREATE (cloudAtlas:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012})\nCREATE (forrestGump:Movie {title: &#x27;Forrest Gump&#x27;, released: 1994})\nCREATE (keanu:Person {name: &#x27;Keanu Reeves&#x27;, born: 1964})\nCREATE (robert:Person {name: &#x27;Robert Zemeckis&#x27;, born: 1951})\nCREATE (tom:Person {name: &#x27;Tom Hanks&#x27;, born: 1956})\nCREATE (tom)-[:ACTED_IN {roles: [&#x27;Forrest&#x27;]}]-&gt;(forrestGump)\nCREATE (tom)-[:ACTED_IN {roles: [&#x27;Zachry&#x27;]}]-&gt;(cloudAtlas)\nCREATE (robert)-[:DIRECTED]-&gt;(forrestGump)\n</code></pre><p>这是生成的图：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-results01-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro results01 arr\"></p>\n<p>第二个数据集是一个由人员、他们工作的公司以及他们喜欢的技术组成的小型网络。您可以在以下章节中找到它的图像。</p>\n<h2>过滤结果</h2>\n<p>到目前为止，您已经匹配了图中的模式，并且总是返回您找到的所有结果。现在让我们看看过滤结果并仅返回您感兴趣的数据子集的选项。这些过滤器条件使用 <code>WHERE</code> 子句表示。此子句允许使用任意数量的布尔表达式、谓词，并与 <code>AND</code>、<code>OR</code>、<code>XOR</code> 和 <code>NOT</code> 组合。最简单的谓词是比较；尤其是相等。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nWHERE m.title = &#x27;The Matrix&#x27;\nRETURN m\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+------------------------------------------------+\n| m                                              |\n+------------------------------------------------+\n| (:Movie {title: &#x27;The Matrix&#x27;, released: 1997}) |\n+------------------------------------------------+\n</code></pre><p>上面的查询使用 <code>WHERE</code> 子句，等效于此查询，该查询在模式匹配中包含条件：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie {title: &#x27;The Matrix&#x27;})\nRETURN m\n</code></pre><p>Cypher 旨在具有灵活性，因此通常有多种编写查询的方法。</p>\n<p>其他选项包括数值比较、匹配正则表达式以及检查列表中是否存在值。</p>\n<p>以下示例中的 <code>WHERE</code> 子句包括正则表达式匹配、大于比较以及测试以查看列表中是否存在值：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[r:ACTED_IN]-&gt;(m:Movie)\nWHERE p.name =~ &#x27;K.+&#x27; OR m.released &gt; 2000 OR &#x27;Neo&#x27; IN r.roles\nRETURN p, r, m\n</code></pre><p>基于给定的逻辑运算符 <code>OR</code> 和图模式 <code>(p:Person)-[r:ACTED_IN]-&gt;(m:Movie)</code>，查询结果必须满足以下要求之一：</p>\n<ul>\n<li>该人的名字以字母“K”开头。</li>\n<li>这部电影是在 2000 年之后发行的。</li>\n<li>角色是“Neo”。</li>\n</ul>\n<p>在我们的例子中，只有第二个条件匹配图模式 <code>(p:Person)-[r:ACTED_IN]-&gt;(m:Movie)</code>，因此输出如下：</p>\n<pre class=\"prettyprint\"><code>Rows: 1\n\n+-------------------------------------------------------------------------------------------------------------------------------+\n| p                                         | r                               | m                                               |\n+-------------------------------------------------------------------------------------------------------------------------------+\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956}) | [:ACTED_IN {roles: [&#x27;Zachry&#x27;]}] | (:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012}) |\n+-------------------------------------------------------------------------------------------------------------------------------+\n</code></pre><p>一个高级方面是模式可以用作谓词。<code>MATCH</code> 扩展了匹配的模式的数量和形状，而模式谓词限制了当前结果集。它只允许满足指定模式的路径通过。正如您可以预期的那样，<code>NOT</code> 的使用只允许不满足指定模式的路径通过。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)-[:ACTED_IN]-&gt;(m)\nWHERE NOT (p)-[:DIRECTED]-&gt;()\nRETURN p, m\n</code></pre><pre class=\"prettyprint\"><code>Rows: 2\n\n+----------------------------------------------------------------------------------------------+\n| p                                         | m                                                |\n+----------------------------------------------------------------------------------------------+\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956}) | (:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012})  |\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956}) | (:Movie {title: &#x27;Forrest Gump&#x27;, released: 1994}) |\n+----------------------------------------------------------------------------------------------+\n</code></pre><p>在这里，您可以找到演员，因为他们支持 <code>ACTED_IN</code> 关系，然后跳过那些曾经 <code>DIRECTED</code> 任何电影的演员。</p>\n<p>还有更高级的过滤方法，例如列表谓词，这将在本节后面讨论。</p>\n<h2>查询值范围</h2>\n<p>经常有查询想要查找特定范围内的数据。日期或数字范围可用于检查特定时间线、年龄值或其他用途中的事件。</p>\n<p>此标准的语法与 SQL 和其他编程语言逻辑结构非常相似，用于检查值的范围。</p>\n<p>以下数据集用于演示这些情况的 Cypher 查询。\n<img src=\"https://neo4j.com/docs/getting-started/_images/people-companies-technologies-rel-property.svg\" alt=\"image\">\n<img src alt=\"people companies technologies rel property\"></p>\n<p>要重现数据集，请运行以下 Cypher 查询：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (diana:Person {name: &quot;Diana&quot;})\nCREATE (melissa:Person {name: &quot;Melissa&quot;, twitter: &quot;@melissa&quot;})\nCREATE (dan:Person {name: &quot;Dan&quot;, twitter: &quot;@dan&quot;, yearsExperience: 6})\nCREATE (sally:Person {name: &quot;Sally&quot;, yearsExperience: 4})\nCREATE (john:Person {name: &quot;John&quot;, yearsExperience: 5})\nCREATE (jennifer:Person {name: &quot;Jennifer&quot;, twitter: &quot;@jennifer&quot;, yearsExperience: 5})\nCREATE (joe:Person {name: &quot;Joe&quot;})\nCREATE (mark:Person {name: &quot;Mark&quot;, twitter: &quot;@mark&quot;})\nCREATE (ann:Person {name: &quot;Ann&quot;})\nCREATE (xyz:Company {name: &quot;XYZ&quot;})\nCREATE (x:Company {name: &quot;Company X&quot;})\nCREATE (a:Company {name: &quot;Company A&quot;})\nCREATE (Neo4j:Company {name: &quot;Neo4j&quot;})\nCREATE (abc:Company {name: &quot;ABC&quot;})\nCREATE (query:Technology {type: &quot;Query Languages&quot;})\nCREATE (etl:Technology {type: &quot;Data ETL&quot;})\nCREATE (integrations:Technology {type: &quot;Integrations&quot;})\nCREATE (graphs:Technology {type: &quot;Graphs&quot;})\nCREATE (dev:Technology {type: &quot;Application Development&quot;})\nCREATE (java:Technology {type: &quot;Java&quot;})\nCREATE (diana)-[:LIKES]-&gt;(query)\nCREATE (melissa)-[:LIKES]-&gt;(query)\nCREATE (dan)-[:LIKES]-&gt;(etl)&lt;-[:LIKES]-(melissa)\nCREATE (xyz)&lt;-[:WORKS_FOR]-(sally)-[:LIKES]-&gt;(integrations)&lt;-[:LIKES]-(dan)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(john)-[:LIKES]-&gt;(java)\nCREATE (john)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:LIKES]-&gt;(java)\nCREATE (john)-[:WORKS_FOR]-&gt;(xyz)\nCREATE (sally)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(melissa)\nCREATE (joe)-[:LIKES]-&gt;(query)\nCREATE (x)&lt;-[:WORKS_FOR]-(diana)&lt;-[:IS_FRIENDS_WITH]-(joe)-[:IS_FRIENDS_WITH]-&gt;(mark)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(jennifer)-[:WORKS_FOR {startYear: 2017}]-&gt;(Neo4j)\nCREATE (ann)&lt;-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]-&gt;(mark)\nCREATE (john)-[:LIKES]-&gt;(dev)&lt;-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]-&gt;(dan)-[:WORKS_FOR]-&gt;(abc)\nCREATE (ann)-[:WORKS_FOR]-&gt;(abc)\nCREATE (a)&lt;-[:WORKS_FOR]-(melissa)-[:LIKES]-&gt;(graphs)&lt;-[:LIKES]-(diana)\n</code></pre><p>假设您想知道谁拥有三到七年的经验。以下代码块显示了这种情况的 Cypher 查询。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)\nWHERE 3 &lt;= p.yearsExperience &lt;= 7\nRETURN p\n</code></pre><p><img src=\"https://neo4j.com/docs/getting-started/_images/cypher-filter-ranges-arr.svg\" alt=\"image\">\n<img src alt=\"cypher filter ranges arr\"></p>\n<h2>测试属性是否存在</h2>\n<p>您可能只对节点或关系上是否存在属性感兴趣。例如，您可能想检查系统中的哪些客户拥有 Twitter 句柄，以便您可以显示相关内容。或者，您可以检查您的所有员工是否都具有开始日期属性，以验证哪些实体可能需要更新。</p>\n<p>请记住：在 Neo4j 中，只有当属性具有值时，该属性才存在（存储）。不会存储空属性。这确保仅为您的节点和关系保留有价值的必要信息。</p>\n<p>要在 Neo4j v5 中编写这种类型的存在检查，您需要使用 <code>IS NOT NULL</code> 谓词来仅包含属性存在的节点或关系。</p>\n<p>Cypher 代码写在下面的块中。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: find all users who have a twitter property\nMATCH (p:Person)\nWHERE p.twitter IS NOT NULL\nRETURN p.name;\n\n&#x2F;&#x2F;Query2: find all WORKS_FOR relationships that have a startYear property\nMATCH (p:Person)-[rel:WORKS_FOR]-&gt;(c:Company)\nWHERE rel.startYear IS NOT NULL\nRETURN p, rel, c;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 4\n\n+------------------------+\n| p.name                 |\n+------------------------+\n| &#x27;Melissa&#x27;              |\n| &#x27;Dan&#x27;                  |\n| &#x27;Jennifer&#x27;             |\n| &#x27;Mark&#x27;                 |\n+------------------------+\n</code></pre><p>Query2 结果：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-filter-exists-relProp-arr.svg\" alt=\"image\">\n<img src alt=\"cypher filter exists relProp arr\"></p>\n<h2>检查字符串 - 部分值、模糊搜索</h2>\n<p>某些场景需要查询语法来匹配字符串中的部分值或广泛类别。要执行这种类型的查询，您需要一些灵活性以及用于字符串匹配和搜索的选项。无论您是寻找以某个值开头、结尾还是包含某个值的字符串，Cypher 都可以轻松且高效地处理它。</p>\n<p>Cypher 中有一些关键字与 <code>WHERE</code> 子句一起使用来测试字符串属性值。<code>STARTS WITH</code> 关键字允许您检查属性的值是否以您指定的字符串开头。使用 <code>CONTAINS</code> 关键字，您可以检查指定的字符串是否是属性值的一部分。<code>ENDS_WITH</code> 关键字检查属性字符串的末尾是否包含您指定的值。</p>\n<p>以下 Cypher 块中包含每个示例。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;check if a property starts with &#x27;M&#x27;\nMATCH (p:Person)\nWHERE p.name STARTS WITH &#x27;M&#x27;\nRETURN p.name;\n\n&#x2F;&#x2F;check if a property contains &#x27;a&#x27;\nMATCH (p:Person)\nWHERE p.name CONTAINS &#x27;a&#x27;\nRETURN p.name;\n\n&#x2F;&#x2F;check if a property ends with &#x27;n&#x27;\nMATCH (p:Person)\nWHERE p.name ENDS WITH &#x27;n&#x27;\nRETURN p.name;\n</code></pre><p>您还可以使用正则表达式来测试字符串的值。例如，您可以查找共享名字的所有 <code>Person</code> 节点，或者您可以找到所有具有特定部门代码的类。</p>\n<p>让我们看一个例子。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)\nWHERE p.name =~ &#x27;Jo.*&#x27;\nRETURN p.name\n</code></pre><pre class=\"prettyprint\"><code>Rows: 2\n\n+--------------------------------+\n| p.name                         |\n+--------------------------------+\n| &#x27;John&#x27;                         |\n| &#x27;Joe&#x27;                          |\n+--------------------------------+\n</code></pre><p>就像在 SQL 和其他语言中一样，您可以检查属性值是否是列表中的值。<code>IN</code> 关键字允许您指定一个值数组，并根据列表中的每个值验证属性的内容。</p>\n<p>这是一个例子：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)\nWHERE p.yearsExperience IN [1, 5, 6]\nRETURN p.name, p.yearsExperience\n</code></pre><pre class=\"prettyprint\"><code>Rows: 3\n\n+--------------+-----------------+\n| p.name       | p.yearsExp      |\n+--------------+-----------------+\n| &#x27;Jennifer&#x27;   | 5               |\n| &#x27;Dan&#x27;        | 6               |\n| &#x27;John&#x27;       | 5               |\n+--------------+-----------------+\n</code></pre><h2>过滤模式</h2>\n<p>使图独一无二的一件事是它对关系的关注。就像您可以根据节点标签或属性过滤查询一样，您也可以根据关系或模式过滤结果。这允许您测试模式是否也具有某种关系或没有，或者是否存在另一种模式。</p>\n<p>以下 Cypher 代码显示了如何完成此操作。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: find which people are friends of someone who works for Neo4j\nMATCH (p:Person)-[r:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWHERE exists((p)-[:WORKS_FOR]-&gt;(:Company {name: &#x27;Neo4j&#x27;}))\nRETURN p, r, friend;\n\n&#x2F;&#x2F;Query2: find Jennifer&#x27;s friends who do not work for a company\nMATCH (p:Person)-[r:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWHERE p.name = &#x27;Jennifer&#x27;\nAND NOT exists((friend)-[:WORKS_FOR]-&gt;(:Company))\nRETURN friend.name;\n</code></pre><p>Query1 结果：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-filter-exists-ptrn-arr.svg\" alt=\"image\">\n<img src alt=\"cypher filter exists ptrn arr\"></p>\n<p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 1\n\n+--------------------------------+\n| friend.name                    |\n+--------------------------------+\n| &#x27;Mark&#x27;                         |\n+--------------------------------+\n</code></pre><h2>可选模式</h2>\n<p>在某些情况下，您可能想要从模式中检索结果，即使它们不匹配整个模式或所有条件。这就是 SQL 中外部联接的工作方式。在 Cypher 中，您可以使用 <code>OPTIONAL MATCH</code> 模式尝试匹配它，但如果它没有找到结果，则这些行将为这些值返回 null。</p>\n<p>您可以通过查询名称以特定字母开头并且可能为公司工作的人员来查看这在 Cypher 中的外观。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Find all people whose name starts with J and who may work for a company.\nMATCH (p:Person)\nWHERE p.name STARTS WITH &#x27;J&#x27;\nOPTIONAL MATCH (p)-[:WORKS_FOR]-(other:Company)\nRETURN p.name, other.name;\n</code></pre><pre class=\"prettyprint\"><code>Rows: 3\n\n+--------------------------------+\n| p.name      | other.name       |\n+--------------------------------+\n| &#x27;Jennifer&#x27;  | &#x27;Neo4j&#x27;          |\n| &#x27;John&#x27;      | &#x27;XYZ&#x27;            |\n| &#x27;Joe&#x27;       | null             |\n+--------------------------------+\n</code></pre><p>请注意，Joe 会被返回，因为他的名字以字母“J”开头，但他的公司名称为 null。那是因为他没有与 <code>COMPANY</code> 节点的 <code>WORKS_FOR</code> 关系。由于您使用了 <code>OPTIONAL MATCH</code>，因此他的 <code>Person</code> 节点仍然从第一个匹配项返回，但未找到第二个匹配项，因此返回 null。</p>\n<p>要查看差异，请尝试在第二个匹配项的前面运行没有 <code>OPTIONAL</code> 的查询。您可以看到不再返回 Joe 的行。那是因为 Cypher 使用 <code>AND</code> 匹配读取语句，因此该人必须匹配第一个条件（名称以“J”开头）和第二个条件（该人为公司工作）。</p>\n<h2>更复杂的模式</h2>\n<p>即使在这一点上，您也能够处理许多简单的图查询。但是，当您想要将模式扩展到单个关系之外时会发生什么？如果您想知道除了 Jennifer 之外还有谁喜欢图，该怎么办？</p>\n<p>我们通过简单地添加到我们的第一个模式或匹配其他模式来处理此功能和许多其他功能。让我们看几个例子。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: find who likes graphs besides Jennifer\nMATCH (j:Person {name: &#x27;Jennifer&#x27;})-[r:LIKES]-(graph:Technology {type: &#x27;Graphs&#x27;})-[r2:LIKES]-(p:Person)\nRETURN p.name;\n\n&#x2F;&#x2F;Query2: find who likes graphs besides Jennifer that she is also friends with\nMATCH (j:Person {name: &#x27;Jennifer&#x27;})-[:LIKES]-&gt;(:Technology {type: &#x27;Graphs&#x27;})&lt;-[:LIKES]-(p:Person),\n      (j)-[:IS_FRIENDS_WITH]-(p)\nRETURN p.name;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 3\n\n+-----------------------+\n| p.name                |\n+-----------------------+\n| &#x27;Diana&#x27;               |\n| &#x27;Mark&#x27;                |\n| &#x27;Melissa&#x27;             |\n+-----------------------+\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 2\n\n+-----------------------+\n| p.name                |\n+-----------------------+\n| &#x27;Mark&#x27;                |\n| &#x27;Melissa&#x27;             |\n+-----------------------+\n</code></pre><p>请注意，在第二个查询中，在第一个 <code>MATCH</code> 行之后使用逗号，并在下一行添加另一个模式以进行匹配。这允许您将模式链接在一起，类似于您上面使用的 <code>WHERE exists(&lt;pattern&gt;)</code> 语法。使用此结构，您可以添加多个不同的模式并将它们链接在一起，从而允许您使用某些模式遍历图的各个部分。</p>\n<h2>返回结果</h2>\n<p>到目前为止，您已经通过它们的变量直接返回了节点、关系和路径。但是，<code>RETURN</code> 子句可以返回任意数量的表达式。但是 Cypher 中的表达式是什么？</p>\n<p>最简单的表达式是文字值。文字值的示例包括：数字、字符串、数组（例如：<code>[1,2,3]</code>）和映射（例如：<code>{name: 'Tom Hanks', born:1964, movies: ['Forrest Gump', ...], count: 13}</code>）。可以使用点语法访问任何节点、关系或映射的各个属性，例如：<code>n.name</code>。可以使用下标检索数组的各个元素或切片，例如：<code>names[0]</code> 和 <code>movies[1..-1]</code>。每个函数评估，例如：<code>length(array)</code>、<code>toInteger('12')</code>、<code>substring('2014-07-01', 0, 4)</code> 和 <code>coalesce(p.nickname, 'n/a')</code> 也是一个表达式。</p>\n<p><code>WHERE</code> 子句中使用的谓词计为布尔表达式。</p>\n<p>可以组合和连接简单表达式以形成更复杂的表达式。</p>\n<p>默认情况下，表达式本身用作列的标签，在许多情况下，您希望使用更易于理解的名称通过 <code>expression AS alias</code> 为其设置别名。别名可以随后用于引用该列。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)\nRETURN\n  p,\n  p.name AS name,\n  toUpper(p.name),\n  coalesce(p.nickname, &#x27;n&#x2F;a&#x27;) AS nickname,\n  {name: p.name, label: head(labels(p))} AS person\n</code></pre><pre class=\"prettyprint\"><code>Rows: 3\n\n+-------------------------------------------------------------------------------------------------------------------------------------------------+\n| p                                               | name              | toUpper(p.name)   | nickname | person                                     |\n+-------------------------------------------------------------------------------------------------------------------------------------------------+\n| (:Person {name: &#x27;Keanu Reeves&#x27;, born: 1964})    | &#x27;Keanu Reeves&#x27;    | &#x27;KEANU REEVES&#x27;    | &#x27;n&#x2F;a&#x27;    | {name: &#x27;Keanu Reeves&#x27;, label: &#x27;Person&#x27;}    |\n| (:Person {name: &#x27;Robert Zemeckis&#x27;, born: 1951}) | &#x27;Robert Zemeckis&#x27; | &#x27;ROBERT ZEMECKIS&#x27; | &#x27;n&#x2F;a&#x27;    | {name: &#x27;Robert Zemeckis&#x27;, label: &#x27;Person&#x27;} |\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956})       | &#x27;Tom Hanks&#x27;       | &#x27;TOM HANKS&#x27;       | &#x27;n&#x2F;a&#x27;    | {name: &#x27;Tom Hanks&#x27;, label: &#x27;Person&#x27;}       |\n+-------------------------------------------------------------------------------------------------------------------------------------------------+\n</code></pre><p>如果您希望仅显示唯一结果，则可以在 <code>RETURN</code> 之后使用 <code>DISTINCT</code> 关键字：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (n)\nRETURN DISTINCT labels(n) AS Labels\n</code></pre><pre class=\"prettyprint\"><code>Rows: 2\n\n+------------+\n| Labels     |\n+------------+\n| [&#x27;Movie&#x27;]  |\n| [&#x27;Person&#x27;] |\n+------------+\n</code></pre><h2>返回唯一结果</h2>\n<p>您可以使用 Cypher 中的 <code>DISTINCT</code> 关键字返回唯一结果。由于节点的多个路径或满足多个条件的节点，您的某些查询可能会返回重复的结果。这种冗余会使结果混乱，并且难以筛选长列表以找到您需要的内容。</p>\n<p>要删除重复的实体，您可以使用 <code>DISTINCT</code> 关键字。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query: find people who have a twitter and like graphs or query languages\nMATCH (user:Person)\nWHERE user.twitter IS NOT null\nWITH user\nMATCH (user)-[:LIKES]-(t:Technology)\nWHERE t.type IN [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;]\nRETURN DISTINCT user.name\n</code></pre><pre class=\"prettyprint\"><code>Query results:\n\nRows: 3\n\n+-----------------------+\n| user.name             |\n+-----------------------+\n| &#x27;Jennifer&#x27;            |\n| &#x27;Melissa&#x27;             |\n| &#x27;Mark&#x27;                |\n+-----------------------+\n</code></pre><p>对于前面的查询，用例是您正在为 Cypher 推出一个新的 Twitter 帐户，其中包含提示和技巧，并且您想要通知拥有 Twitter 帐户并且喜欢图或查询语言的用户。查询的前两行查找具有 Twitter 句柄的 <code>Person</code> 节点。然后，您使用 <code>WITH</code> 将这些用户传递到下一个 <code>MATCH</code>，您可以在其中找出该人是否喜欢图或查询语言。请注意，在没有 <code>DISTINCT</code> 关键字的情况下运行此语句会导致“Melissa”显示两次。这是因为她喜欢图，而且她也喜欢查询语言。当使用 <code>DISTINCT</code> 时，您只会检索唯一用户。</p>\n<h2>限制结果数</h2>\n<p>有时您想要一个抽样集，或者您只想一次提取这么多结果来更新或处理。<code>LIMIT</code> 关键字获取查询的输出，并根据您指定的数字限制返回的卷。</p>\n<p>例如，您可以找到图中每个人的朋友数。如果该图有成千上万或数百万个节点和关系，则返回的结果数将是巨大的。如果您只关心拥有最多朋友的前三个人怎么办？让我们为此编写一个查询！</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query: find the top 3 people who have the most friends\nMATCH (p:Person)-[r:IS_FRIENDS_WITH]-(other:Person)\nRETURN p.name, count(other.name) AS numberOfFriends\nORDER BY numberOfFriends DESC\nLIMIT 3\n</code></pre><pre class=\"prettyprint\"><code>Rows: 3\n\n+--------------------------------+\n| p.name      | numberOfFriends  |\n+--------------------------------+\n| &#x27;Jennifer&#x27;  | 5                |\n| &#x27;Mark&#x27;      | 2                |\n| &#x27;Ann&#x27;       | 2                |\n+--------------------------------+\n</code></pre><p>该查询提取人员以及他们连接的朋友，并返回人员姓名和他们的朋友的计数。您可以只运行查询的那么多内容并返回名称和朋友计数的混乱列表，但您可能想要根据每个人拥有的朋友数量（从顶部最大的数字开始 (DESC)）对列表进行排序。您也可以运行查询的那么多内容以查看所有排序的朋友和计数，但在上面的示例中，已从图中提取了拥有最多朋友的前三个人。<code>LIMIT</code> 从排序列表中提取顶部结果。</p>\n<p>尝试通过删除 <code>ORDER BY</code> 和 <code>LIMIT</code> 行来混合查询，然后分别添加每一行。请注意，仅删除 <code>ORDER BY</code> 行会从列表中提取起始三个值，从而获得返回结果的随机抽样。</p>\n<h2>聚合信息</h2>\n<p>在许多情况下，我们希望在遍历图中的模式时聚合或分组遇到的数据。在 Cypher 中，聚合发生在 <code>RETURN</code> 子句中，同时计算最终结果。支持许多常见的聚合函数，例如 <code>count</code>、<code>sum</code>、<code>avg</code>、<code>min</code> 和 <code>max</code>，但还有更多。</p>\n<p>可以通过以下方式实现计算电影数据库中的人数：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Person)\nRETURN count(*) AS people\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+--------+\n| people |\n+--------+\n| 3      |\n+--------+\n</code></pre><p>如果要跳过空值，请使用函数 <code>count(variable)</code>。</p>\n<p>要仅聚合唯一值，请使用 <code>DISTINCT</code> 运算符，例如：<code>count(DISTINCT role)</code>。</p>\n<p>聚合在 Cypher 中隐式工作。您指定要聚合的结果列。Cypher 使用所有非聚合列作为分组键。</p>\n<p>聚合会影响在排序或后续查询部分中仍然可见的数据。</p>\n<p>以下语句找出演员和导演一起工作的频率：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (actor:Person)-[:ACTED_IN]-&gt;(movie:Movie)&lt;-[:DIRECTED]-(director:Person)\nRETURN actor, director, count(*) AS collaborations\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+--------------------------------------------------------------------------------------------------------------+\n| actor                                     | director                                        | collaborations |\n+--------------------------------------------------------------------------------------------------------------+\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956}) | (:Person {name: &#x27;Robert Zemeckis&#x27;, born: 1951}) | 1              |\n+--------------------------------------------------------------------------------------------------------------+\n</code></pre><p>有三种不同的方法可以使用 <code>count()</code> 函数：</p>\n<ul>\n<li><code>count(*)</code>：计算结果并返回匹配行数。</li>\n<li><code>count(n)</code>：计算 <code>n</code> 的出现次数（排除空值）。您可以指定节点、关系或属性，供 Cypher 计数。</li>\n<li><code>count(DISTINCT variable)</code>：<code>DISTINCT</code> 运算符从结果中删除重复项。</li>\n</ul>\n<p>在数据集“人员、技术和公司”中，某些 <code>Person</code> 节点具有 Twitter 句柄，而另一些则没有。如果您运行下面的第一个示例查询，您将看到 <code>twitter</code> 属性对四个人有一个值，而对其他五个人则为 null。第二个和第三个查询显示了如何使用不同的计数选项。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: see the list of Twitter handle values for Person nodes\nMATCH (p:Person)\nRETURN p.twitter;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 9\n\n+--------------+\n| p.twitter    |\n+--------------+\n| &#x27;@jennifer&#x27;  |\n| &#x27;@melissa&#x27;   |\n| null         |\n| &#x27;@mark&#x27;      |\n| &#x27;@dan&#x27;       |\n| null         |\n| null         |\n| null         |\n| null         |\n+--------------+\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query2: count of the non-null &#96;twitter&#96; property of the Person nodes\nMATCH (p:Person)\nRETURN count(p.twitter);\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 1\n\n+-------------------+\n| count(p.twitter)  |\n+-------------------+\n| 4                 |\n+-------------------+\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query3: count on the Person nodes\nMATCH (p:Person)\nRETURN count(*);\n</code></pre><p>Query3 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 1\n\n+-------------------+\n| count(*)          |\n+-------------------+\n| 9                 |\n+-------------------+\n</code></pre><h2>收集聚合</h2>\n<p>一个非常有用的聚合函数是 <code>collect(expression)</code>，它返回由表达式返回的值的单个聚合列表。这在许多情况下非常有用，因为在聚合时不会丢失任何详细信息。</p>\n<p><code>collect()</code> 非常适合检索典型的父子结构，其中每行返回一个核心实体（父级、根或头），所有依赖信息都在使用 <code>collect()</code> 创建的关联列表中。这意味着无需为每个子行重复父信息，也无需运行 n+1 个语句来单独检索父及其子项。</p>\n<p>以下语句可用于检索数据库中每部电影的演员阵容：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)&lt;-[:ACTED_IN]-(a:Person)\nRETURN m.title AS movie, collect(a.name) AS cast, count(*) AS actors\n</code></pre><pre class=\"prettyprint\"><code>Rows: 2\n\n+-----------------------------------------+\n| movie          | cast          | actors |\n+-----------------------------------------+\n| &#x27;Forrest Gump&#x27; | [&#x27;Tom Hanks&#x27;] | 1      |\n| &#x27;Cloud Atlas&#x27;  | [&#x27;Tom Hanks&#x27;] | 1      |\n+-----------------------------------------+\n</code></pre><p>由 <code>collect()</code> 创建的列表可以从使用 Cypher 结果的客户端使用，也可以直接在具有任何列表函数或谓词的语句中使用。</p>\n<h2>循环遍历列表值</h2>\n<p>如果您有一个想要检查或分离值的列表，Cypher 提供了 <code>UNWIND</code> 子句。这与 <code>collect()</code> 的作用相反，并将列表分离为单独行上的各个值。</p>\n<p>在导入数据以及日常数组和其他类型的列表时，<code>UNWIND</code> 经常用于循环遍历 JSON 和 XML 对象。让我们看几个示例，我们假设某人喜欢的技术也意味着他们对每项技术都有一些经验。如果您有兴趣雇用熟悉图或查询语言的人员，您可以编写以下查询来查找要面试的人员。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: for a list of techRequirements, look for people who have each skill\nWITH [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;] AS techRequirements\nUNWIND techRequirements AS technology\nMATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})\nRETURN t.type, collect(p.name) AS potentialCandidates;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 2\n\n+-------------------+------------------------------------------+\n| t.type            | potentialCandidates                      |\n+-------------------+------------------------------------------+\n| &#x27;Graphs&#x27;          | [&#x27;Diana&#x27;, &#x27;Mark&#x27;, &#x27;Melissa&#x27;, &#x27;Jennifer&#x27;] |\n| &#x27;Query Languages&#x27; | [&#x27;Diana&#x27;, &#x27;Melissa&#x27;, &#x27;Joe&#x27;]              |\n+-------------------+------------------------------------------+\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query2: for numbers in a list, find candidates who have that many years of experience\nWITH [4, 5, 6, 7] AS experienceRange\nUNWIND experienceRange AS number\nMATCH (p:Person)\nWHERE p.yearsExp = number\nRETURN p.name, p.yearsExp;\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 4\n\n+--------------+-----------------+\n| p.name       | p.yearsExp      |\n+--------------+-----------------+\n| &#x27;Sally&#x27;      | 4               |\n| &#x27;Jennifer&#x27;   | 5               |\n| &#x27;John&#x27;       | 5               |\n| &#x27;Dan&#x27;        | 6               |\n+--------------+-----------------+\n</code></pre><h2>排序和分页</h2>\n<p>通常在使用 <code>count(x)</code> 聚合后进行排序和分页。</p>\n<p>排序是使用 <code>ORDER BY expression [ASC|DESC]</code> 子句完成的。该表达式可以是任何表达式，只要它可以从返回的信息中计算出来。</p>\n<p>例如，如果您返回 <code>person.name</code>，您仍然可以 <code>ORDER BY person.age</code>，因为两者都可以从 <code>person</code> 引用访问。您不能按未返回的内容排序。这对于聚合和 <code>DISTINCT</code> 返回值尤其重要，因为两者都会删除聚合数据的可见性。</p>\n<p>分页是使用 <code>SKIP {offset}</code> 和 <code>LIMIT {count}</code> 子句完成的。</p>\n<p>一个常见的模式是聚合计数（分数或频率），按其排序，并且仅返回前 n 个条目。</p>\n<p>例如，要找到最多产的演员，您可以这样做：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (a:Person)-[:ACTED_IN]-&gt;(m:Movie)\nRETURN a, count(*) AS appearances\nORDER BY appearances DESC LIMIT 10\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+---------------------------------------------------------+\n| a                                         | appearances |\n+---------------------------------------------------------+\n| (:Person {name: &#x27;Tom Hanks&#x27;, born: 1956}) | 2           |\n+---------------------------------------------------------+\n</code></pre><h2>排序结果</h2>\n<p>如果您可以按最多或最少的经验对我们先前示例中的潜在招聘候选人列表进行排序，那么它可能会更有用。或者，您可能想要按年龄对我们所有的人员进行排名。</p>\n<p><code>ORDER BY</code> 关键字根据您在升序或降序中指定的值对结果进行排序（升序是默认值）。让我们使用与 <code>UNWIND</code> 相同的示例查询，看看如何对候选人进行排序。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: for a list of techRequirements, look for people who have each skill\nWITH [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;] AS techRequirements\nUNWIND techRequirements AS technology\nMATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})\nWITH t.type AS technology, p.name AS personName\nORDER BY technology, personName\nRETURN technology, collect(personName) AS potentialCandidates;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 2\n\n+-------------------+------------------------------------------+\n| technology        | potentialCandidates                      |\n+-------------------+------------------------------------------+\n| &#x27;Graphs&#x27;          | [&#x27;Diana&#x27;, &#x27;Jennifer&#x27;, &#x27;Mark&#x27;, &#x27;Melissa&#x27;] |\n| &#x27;Query Languages&#x27; | [&#x27;Diana&#x27;, &#x27;Joe&#x27;]                           |\n+-------------------+------------------------------------------+\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query2: for numbers in a list, find candidates who have that many years of experience\nWITH [4, 5, 6, 7] AS experienceRange\nUNWIND experienceRange AS number\nMATCH (p:Person)\nWHERE p.yearsExp = number\nRETURN p.name, p.yearsExp ORDER BY p.yearsExp DESC;\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 4\n\n+--------------+-----------------+\n| p.name       | p.yearsExp      |\n+--------------+-----------------+\n| &#x27;Dan&#x27;        | 6               |\n| &#x27;Jennifer&#x27;   | 5               |\n| &#x27;John&#x27;       | 5               |\n| &#x27;Sally&#x27;      | 4               |\n+--------------+-----------------+\n</code></pre><p>请注意，第一个查询必须先按人员姓名排序，然后才能将值收集到列表中。如果您不先排序（将 <code>ORDER BY</code> 放在 <code>RETURN</code> 子句之后），您将根据列表的大小而不是列表中值的首字母进行排序。结果也被排序为两个值：技术，然后是人。这允许您对技术进行排序，以便将喜欢某项技术的所有人员列在一起。</p>\n<p>您可以通过运行以下查询来尝试按两个值或一个值进行排序的差异：</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;only sorted by person&#x27;s name in alphabetical order\nWITH [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;] AS techRequirements\nUNWIND techRequirements AS technology\nMATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})\nWITH t.type AS technology, p.name AS personName\nORDER BY personName\nRETURN technology, personName;\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;only sorted by technology (person names are out of order)\nWITH [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;] AS techRequirements\nUNWIND techRequirements AS technology\nMATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})\nWITH t.type AS technology, p.name AS personName\nORDER BY technology\nRETURN technology, personName;\n</code></pre><pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;sorted by technology, then by person&#x27;s name\nWITH [&#x27;Graphs&#x27;,&#x27;Query Languages&#x27;] AS techRequirements\nUNWIND techRequirements AS technology\nMATCH (p:Person)-[r:LIKES]-(t:Technology {type: technology})\nWITH t.type AS technology, p.name AS personName\nORDER BY technology, personName\nRETURN technology, personName;\n</code></pre><h2>计算列表中的值</h2>\n<p>如果您有一个值列表，您还可以使用 <code>size()</code> 函数查找该列表中的项目数或计算表达式的大小。以下示例返回找到的项目数。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query1: find number of items in collected list\nMATCH (p:Person)-[:IS_FRIENDS_WITH]-&gt;(friend:Person)\nRETURN p.name, size(collect(friend.name)) AS numberOfFriends;\n</code></pre><p>Query1 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 4\n\n+--------------+-----------------+\n| p.name       | numberOfFriends |\n+--------------+-----------------+\n| &#x27;John&#x27;       | 1               |\n| &#x27;Jennifer&#x27;   | 5               |\n| &#x27;Ann&#x27;        | 1               |\n| &#x27;Joe&#x27;        | 2               |\n+--------------+-----------------+\n</code></pre><p>在 Neo4j v5 中，如果您需要查找关系模式的数量，请使用 <code>COUNT {}</code> 表达式。请看以下 Cypher 查询示例。</p>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F;Query2: find number of friends who have other friends\nMATCH (p:Person)-[:IS_FRIENDS_WITH]-&gt;(friend:Person)\nWHERE count{(friend)-[:IS_FRIENDS_WITH]-(:Person)} &gt; 1\nRETURN p.name, collect(friend.name) AS friends, count{(friend)-[:IS_FRIENDS_WITH]-(:Person)} AS numberOfFoFs;\n</code></pre><p>Query2 结果：</p>\n<pre class=\"prettyprint\"><code>Rows: 3\n\n+--------------+----------------------------------+---------------+\n| p.name       | friends                          | numberOfFoFs  |\n+--------------+----------------------------------+---------------+\n| &#x27;Joe&#x27;        | [&#x27;Mark&#x27;]                         | 2             |\n| &#x27;Jennifer&#x27;   | [&#x27;Mark&#x27;, &#x27;John&#x27;, &#x27;Sally&#x27;, &#x27;Ann&#x27;] | 2             |\n| &#x27;John&#x27;       | [&#x27;Sally&#x27;]                        | 2             |\n+--------------+----------------------------------+---------------+\n</code></pre><p>资源</p>\n<ul>\n<li>Neo4j Cypher 手册：WITH、UNWIND 等</li>\n<li>Neo4j Cypher 手册：聚合</li>\n<li>Neo4j Cypher 手册：size()</li>\n</ul>\n</div>","title":"Neo4j官方教程：第10节，获取正确的结果","last_reply_at":"2025-04-09T02:28:30.489Z","good":true,"top":false,"reply_count":0,"visit_count":3223,"create_at":"2025-04-09T02:28:30.489Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67f5d4a0455186f56d9f4134","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher-intro/patterns-in-practice/\">https://neo4j.com/docs/getting-started/cypher-intro/patterns-in-practice/</a></p>\n<h1>实践中的模式</h1>\n<h2>创建和返回数据</h2>\n<p>让我们首先看看允许您创建数据的子句。</p>\n<p>要添加数据，您只需使用您已经知道的模式。通过提供模式，您可以指定哪些图结构、标签和属性要成为图的一部分。</p>\n<p>显然，最简单的子句称为 <code>CREATE</code>。它创建您指定的模式。</p>\n<p>对于您到目前为止所看到的模式，这可能如下所示：</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (:Movie {title: &#x27;The Matrix&#x27;, released: 1997})\n</code></pre><p>如果您运行此语句，Cypher® 将返回更改的数量：在本例中，添加一个节点、一个标签和两个属性。</p>\n<pre class=\"prettyprint\"><code>Created Nodes: 1\nAdded Labels: 1\nSet Properties: 2\nRows: 0\n</code></pre><p>由于您从一个空数据库开始，因此您现在有一个数据库，其中包含一个节点：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice01-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice01 arr\"></p>\n<p>如果您还想返回创建的数据，您可以添加一个 <code>RETURN</code> 子句，该子句引用您已分配给模式元素的变量。\nCypher 中的 <code>RETURN</code> 关键字指定您可能希望从 Cypher 查询返回的值或结果。\n您可以告诉 Cypher 返回节点、关系、节点和关系属性或查询结果中的模式。\n执行写入过程时不需要 <code>RETURN</code>，但读取时需要。\n当使用 <code>RETURN</code> 时，前面讨论的节点和关系变量变得很重要。</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (p:Person {name: &#x27;Keanu Reeves&#x27;, born: 1964})\nRETURN p\n</code></pre><p>这是返回的内容：</p>\n<pre class=\"prettyprint\"><code>Created Nodes: 1\nAdded Labels: 1\nSet Properties: 2\nRows: 1\n\n+----------------------------------------------+\n| p                                            |\n+----------------------------------------------+\n| (:Person {name: &#x27;Keanu Reeves&#x27;, born: 1964}) |\n+----------------------------------------------+\n</code></pre><p>如果要创建多个元素，可以用逗号分隔元素或使用多个 <code>CREATE</code> 语句。</p>\n<p>当然，您还可以创建更复杂的结构，例如包含有关角色的信息的 <code>ACTED_IN</code> 关系，或导演的 <code>DIRECTED</code> 关系。</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (a:Person {name: &#x27;Tom Hanks&#x27;, born: 1956})-[r:ACTED_IN {roles: [&#x27;Forrest&#x27;]}]-&gt;(m:Movie {title: &#x27;Forrest Gump&#x27;, released: 1994})\nCREATE (d:Person {name: &#x27;Robert Zemeckis&#x27;, born: 1951})-[:DIRECTED]-&gt;(m)\nRETURN a, d, r, m\n</code></pre><p>这是更新后的图的一部分：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice02-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice02 arr\"></p>\n<p>在大多数情况下，您希望将新数据添加到现有结构。这需要知道如何在图数据中查找现有模式，这将在下一节中介绍。</p>\n<h2>匹配模式</h2>\n<p>匹配模式是 <code>MATCH</code> 语句的任务。您将到目前为止使用的相同类型的模式传递给 <code>MATCH</code>，以描述您要查找的内容。它类似于按示例查询，只是您的示例还包括结构。要返回节点、关系、属性或模式，您需要在 <code>MATCH</code> 子句中为要返回的数据指定变量。</p>\n<p><code>MATCH</code> 语句搜索您指定的模式，并为每个成功的模式匹配返回一行。</p>\n<p>要查找您到目前为止创建的数据，您可以开始查找所有带有 <code>Movie</code> 标签的节点。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie)\nRETURN m\n</code></pre><p>结果如下：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice03-arr.svg\" alt=\"image\"></p>\n<p><img src alt=\"cypher intro patterns in practice03 arr\"></p>\n<p>这应该显示《黑客帝国》和《阿甘正传》。</p>\n<p>您还可以查找特定的人，例如基努·里维斯。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Keanu Reeves&#x27;})\nRETURN p\n</code></pre><p>此查询返回匹配的节点：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice04-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice04 arr\"></p>\n<p>请注意，您只提供足够的信息来查找节点，并非所有属性都是必需的。在大多数情况下，您都有关键属性，例如 SSN、ISBN、电子邮件、登录名、地理位置或产品代码来查找。</p>\n<p>您还可以找到更有趣的连接，例如，汤姆·汉克斯出演的电影的标题和他扮演的角色。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Tom Hanks&#x27;})-[r:ACTED_IN]-&gt;(m:Movie)\nRETURN m.title, r.roles\n</code></pre><pre class=\"prettyprint\"><code>Rows: 1\n\n+------------------------------+\n| m.title        | r.roles     |\n+------------------------------+\n| &#x27;Forrest Gump&#x27; | [&#x27;Forrest&#x27;] |\n+------------------------------+\n</code></pre><p>在本例中，您只返回了您感兴趣的节点和关系的属性。您可以通过点表示法 <code>identifier.property</code> 在任何地方访问它们。</p>\n<p>当然，这只列出了汤姆·汉克斯在《阿甘正传》中扮演的 Forrest 角色，因为这就是您添加的所有数据。</p>\n<p>现在您已经知道足够多的知识来将新节点添加到现有节点，并且可以将 <code>MATCH</code> 和 <code>CREATE</code> 组合起来以将结构附加到图中。</p>\n<h2>Cypher 示例</h2>\n<p>让我们看一些使用 <code>MATCH</code> 和 <code>RETURN</code> 关键字的示例。每个后续示例都比前一个示例更复杂。最后两个示例首先解释了我们试图实现的目标。如果您单击每个 Cypher 代码段下方的“运行查询”按钮，您可以在图或表的格式中查看结果。</p>\n<p><strong>示例 1</strong>：查找图中带有标签 <code>Person</code> 的节点。请注意，如果要检索 <code>RETURN</code> 子句中的节点，则必须为 <code>Person</code> 节点使用一个变量，例如 <code>p</code>。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person)\nRETURN p\nLIMIT 1\n</code></pre><p><strong>示例 2</strong>：查找图中名称为“Tom Hanks”的 <code>Person</code> 节点。请记住，您可以随意命名您的变量，只要您稍后引用相同的名称即可。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (tom:Person {name: &#x27;Tom Hanks&#x27;})\nRETURN tom\n</code></pre><p><strong>示例 3</strong>：查找汤姆·汉克斯导演的电影。</p>\n<p>说明：首先，您应该找到汤姆·汉克斯的 <code>Person</code> 节点，然后找到他连接到的 <code>Movie</code> 节点。为此，您必须从汤姆·汉克斯的 <code>Person</code> 节点到 <code>Movie</code> 节点遵循 <code>DIRECTED</code> 关系。您还指定了 <code>Movie</code> 的标签，以便查询仅查看带有该标签的节点。由于您只关心在此查询中返回电影，因此您需要为该节点提供一个变量（<code>movie</code>），但不需要为 <code>Person</code> 节点或 <code>DIRECTED</code> 关系提供变量。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Person {name: &#x27;Tom Hanks&#x27;})-[:DIRECTED]-&gt;(movie:Movie)\nRETURN movie\n</code></pre><p><strong>示例 4</strong>：查找汤姆·汉克斯导演的电影，但这次只返回电影的标题。</p>\n<p>说明：此查询与上一个查询类似。示例 3 返回了整个 <code>Movie</code> 节点及其所有属性。对于此示例，您仍然需要找到汤姆的电影，但现在您只关心它们的标题。您应该使用语法 <code>variable.property</code> 访问节点的 <code>title</code> 属性以返回名称值。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (:Person {name: &#x27;Tom Hanks&#x27;})-[:DIRECTED]-&gt;(movie:Movie)\nRETURN movie.title\n</code></pre><h2>别名返回值</h2>\n<p>并非所有属性都像上面示例中的 <code>movie.title</code> 那样简单。由于属性长度、多字描述、开发人员术语和其他快捷方式，某些属性的名称很差。这些命名约定可能难以阅读，尤其是在报告和其他面向用户的界面上。</p>\n<h3>命名不佳的属性</h3>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F; 命名不佳的属性\nMATCH (tom:Person {name:&#x27;Tom Hanks&#x27;})-[rel:DIRECTED]-(movie:Movie)\nRETURN tom.name, tom.born, movie.title, movie.released\n</code></pre><p>就像 SQL 一样，您可以使用 <code>AS</code> 关键字重命名返回结果，并使用更清晰的名称为属性设置别名。</p>\n<h3>使用别名获得更清晰的结果</h3>\n<pre class=\"prettyprint language-cypher\"><code>&#x2F;&#x2F; 使用别名获得更清晰的打印结果\nMATCH (tom:Person {name:&#x27;Tom Hanks&#x27;})-[rel:DIRECTED]-(movie:Movie)\nRETURN tom.name AS name, tom.born AS &#96;Year Born&#96;, movie.title AS title, movie.released AS &#96;Year Released&#96;\n</code></pre><p>您可以通过在别名前后使用反引号字符来指定包含空格的返回别名（<code>movie.released AS Year Released</code>）。如果您没有包含空格的别名，则无需使用反引号。</p>\n<h2>附加结构</h2>\n<p>要使用新信息扩展图，首先要匹配现有的连接点，然后使用关系将新创建的节点附加到它们。像这样可以为汤姆·汉克斯添加一部新电影《云图》：</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (p:Person {name: &#x27;Tom Hanks&#x27;})\nCREATE (m:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012})\nCREATE (p)-[r:ACTED_IN {roles: [&#x27;Zachry&#x27;]}]-&gt;(m)\nRETURN p, r, m\n</code></pre><p>这是数据库中的结构：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice05-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice05 arr\"></p>\n<p>重要的是要记住，您可以为节点和关系分配变量，并在以后使用它们，无论它们是创建的还是匹配的。</p>\n<p>可以在单个 <code>CREATE</code> 子句中附加节点和关系。但是，为了提高可读性，将它们分开是有帮助的。</p>\n<p><code>MATCH</code> 和 <code>CREATE</code> 组合的一个棘手方面是，每个匹配的模式都会得到一行。这会导致后续的 <code>CREATE</code> 语句为每一行执行一次。在许多情况下，这正是您想要的。如果不是有意的，请将 <code>CREATE</code> 语句移动到 <code>MATCH</code> 之前，或者使用稍后讨论的方法更改查询的基数，或者使用下一个子句的获取或创建语义：<code>MERGE</code>。</p>\n<h2>完成模式</h2>\n<p>每当您从外部系统获取数据或不确定某些信息是否已存在于图中时，您都希望能够表达可重复（幂等）的更新操作。在 Cypher 中，<code>MERGE</code> 子句具有此功能。它的作用类似于 <code>MATCH</code> 或 <code>CREATE</code> 的组合，它在创建数据之前检查数据是否存在。使用 <code>MERGE</code>，您可以定义要查找或创建的模式。通常，与 <code>MATCH</code> 一样，您只想在核心模式中包含要查找的关键属性。<code>MERGE</code> 允许您提供要在 <code>ON CREATE</code> 上设置的其他属性。</p>\n<p>如果您不知道您的图是否已经包含《云图》，您可以再次合并它。</p>\n<pre class=\"prettyprint language-cypher\"><code>MERGE (m:Movie {title: &#x27;Cloud Atlas&#x27;})\nON CREATE SET m.released = 2012\nRETURN m\n</code></pre><pre class=\"prettyprint\"><code>Created Nodes: 1\nAdded Labels: 1\nSet Properties: 2\nRows: 1\n\n+-------------------------------------------------+\n| m                                               |\n+-------------------------------------------------+\n| (:Movie {title: &#x27;Cloud Atlas&#x27;, released: 2012}) |\n+-------------------------------------------------+\n</code></pre><p>在这两种情况下，您都会得到一个结果：要么是图中已经存在的数据（可能不止一行），要么是一个新创建的 <code>Movie</code> 节点。</p>\n<p>没有任何先前分配变量的 <code>MERGE</code> 子句要么匹配完整模式，要么创建完整模式。它永远不会产生模式中匹配和创建的部分混合。要实现部分匹配/创建，请确保对不应受影响的部分使用已定义的变量。</p>\n<p>因此，最重要的是，<code>MERGE</code> 确保您不能创建重复的信息或结构，但它需要首先检查现有匹配项的成本。尤其是在大型图上，扫描一组带有标签的节点以查找特定属性可能代价高昂。您可以通过创建支持索引或约束来缓解这种情况，这将在后面的章节中讨论。但这仍然不是免费的，因此，只要您确定不会创建重复数据，请使用 <code>CREATE</code> 而不是 <code>MERGE</code>。</p>\n<p><code>MERGE</code> 还可以断言仅创建一次关系。为此，您必须从先前的模式匹配中传入两个节点。</p>\n<pre class=\"prettyprint language-cypher\"><code>MATCH (m:Movie {title: &#x27;Cloud Atlas&#x27;})\nMATCH (p:Person {name: &#x27;Tom Hanks&#x27;})\nMERGE (p)-[r:ACTED_IN]-&gt;(m)\nON CREATE SET r.roles =[&#x27;Zachry&#x27;]\nRETURN p, r, m\n</code></pre><p><img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice06-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice06 arr\"></p>\n<p>如果关系的方向是任意的，您可以省略箭头。<code>MERGE</code> 检查任一方向的关系，如果没有匹配的关系，则创建一个新的有向关系。</p>\n<p>如果您选择仅从前面的子句中传入一个节点，则 <code>MERGE</code> 提供了一个有趣的功能。它仅在给定模式的提供的节点的直接邻域内匹配，如果未找到该模式，则创建它。这对于创建树结构非常有用。</p>\n<pre class=\"prettyprint language-cypher\"><code>CREATE (y:Year {year: 2014})\nMERGE (y)&lt;-[:IN_YEAR]-(m10:Month {month: 10})\nMERGE (y)&lt;-[:IN_YEAR]-(m11:Month {month: 11})\nRETURN y, m10, m11\n</code></pre><p>这是创建的图结构：\n<img src=\"https://neo4j.com/docs/getting-started/_images/cypher-intro-patterns-in-practice07-arr.svg\" alt=\"image\">\n<img src alt=\"cypher intro patterns in practice07 arr\"></p>\n<p>这里没有对两个 <code>Month</code> 节点进行全局搜索；仅在 2014 <code>Year</code> 节点的上下文中搜索它们。</p>\n<h2>代码挑战</h2>\n<p>现在了解了基础知识，请使用下面的部分构建一个 Cypher 语句，以查找汤姆·汉克斯 <code>DIRECTED</code> 的每个 <code>Movie</code> 的标题和发行年份。单击这些部分以按顺序添加它们，完成后，单击“运行查询”以查看您是否正确。您可以单击代码块内的任何查询部分以将其删除。</p>\n<p>从下面的选项中选择以完成查询：</p>\n<pre class=\"prettyprint\"><code>{name:})-[:MovieRETURNPerson&quot;Tom Hanks&quot;)m.title, m.released]-&gt;(m:DIRECTED(p:MATCH\n</code></pre></div>","title":"Neo4j官方教程：第9节，实践中的模式","last_reply_at":"2025-04-09T02:00:00.826Z","good":true,"top":false,"reply_count":0,"visit_count":2965,"create_at":"2025-04-09T02:00:00.826Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}},{"id":"67f5cf0f455186f56d9f4133","author_id":"5813fc27151711bf08e3384e","tab":"share","content":"<div class=\"markdown-text\"><p><a href=\"http://neo4j.com.cn/topic/67f4cf91455186f56d9f412f\">教程目录</a>\n引自：<a href=\"https://neo4j.com/docs/getting-started/cypher/\">https://neo4j.com/docs/getting-started/cypher/</a></p>\n<h1>模式</h1>\n<p>Neo4j 的属性图由节点和关系组成，它们都可以具有属性。节点表示实体，例如概念、事件、地点和事物。关系连接成对的节点。</p>\n<p>但是，节点和关系可以被认为是低级构建块。属性图的真正优势在于它能够编码连接的节点和关系的模式。单个节点或关系通常编码的信息很少，但是节点和关系的模式可以编码任意复杂的想法。</p>\n<p>Cypher®（Neo4j 的查询语言）强烈基于模式。具体来说，模式用于匹配所需的图结构。一旦找到或创建了匹配的结构，Neo4j 就可以使用它进行进一步处理。</p>\n<p>一个简单的模式（只有一个关系）连接一对节点（或者，偶尔，一个节点连接到自身）。例如，一个人 <code>LIVES_IN</code> 一个城市，或者一个城市是 <code>PART_OF</code> 一个国家。</p>\n<p>使用多个关系的复杂模式可以表达任意复杂的概念，并支持各种有趣的用例。例如，我们可能想要匹配一个人 <code>LIVES_IN</code> 一个国家的实例。以下 Cypher 代码将两个简单的模式组合成一个稍微复杂的模式，该模式执行此匹配：</p>\n<pre class=\"prettyprint language-cypher\"><code>(:Person) -[:LIVES_IN]-&gt; (:City) -[:PART_OF]-&gt; (:Country)\n</code></pre><p>由图标和箭头组成的图通常用于可视化图。文本注释提供标签，定义属性等。</p>\n<h2>节点语法</h2>\n<p>Cypher 使用一对括号来表示一个节点：<code>()</code>。这让人联想到一个圆形或一个带有圆形端盖的矩形。以下是一些节点的示例，提供了不同类型和数量的详细信息：</p>\n<pre class=\"prettyprint\"><code>()\n(matrix)\n(:Movie)\n(matrix:Movie)\n(matrix:Movie {title: &#x27;The Matrix&#x27;})\n(matrix:Movie {title: &#x27;The Matrix&#x27;, released: 1997})\n</code></pre><p>最简单的形式 <code>()</code> 表示一个匿名的、未表征的节点。如果我们要稍后引用该节点，我们可以添加一个变量，例如：<code>(matrix)</code>。变量仅限于单个语句。它在另一个语句中可能具有不同的含义或没有意义。</p>\n<p><code>:Movie</code> 模式声明节点的标签。这允许我们限制模式，防止它匹配（例如）此位置具有 <code>Actor</code> 节点的结构。</p>\n<p>节点的属性（例如 <code>title</code>）表示为键值对的列表，括在一对大括号内，例如：<code>{name: 'Keanu Reeves'}</code>。属性可用于存储信息和/或限制模式。</p>\n<h2>关系语法</h2>\n<p>Cypher 使用一对破折号 (<code>--</code>) 来表示无向关系。有向关系在一端有一个箭头 (<code>&lt;--</code>，<code>--&gt;</code>)。带括号的表达式 (<code>[...]</code>) 可用于添加详细信息。这可能包括变量、属性和类型信息：</p>\n<pre class=\"prettyprint\"><code>--&gt;\n-[role]-&gt;\n-[:ACTED_IN]-&gt;\n-[role:ACTED_IN]-&gt;\n-[role:ACTED_IN {roles: [&#x27;Neo&#x27;]}]-&gt;\n</code></pre><p>在关系的括号对中找到的语法和语义与节点括号之间使用的语法和语义非常相似。可以定义一个变量（例如，<code>role</code>），以便在语句中的其他地方使用。关系类型（例如，<code>:ACTED_IN</code>）类似于节点的标签。属性（例如，<code>roles</code>）与节点属性完全等效。</p>\n<h2>模式语法</h2>\n<p>结合节点和关系的语法，我们可以表达模式。以下可能是此域中的一个简单模式（或事实）：</p>\n<pre class=\"prettyprint language-cypher\"><code>(keanu:Person:Actor {name: &#x27;Keanu Reeves&#x27;})-[role:ACTED_IN {roles: [&#x27;Neo&#x27;]}]-&gt;(matrix:Movie {title: &#x27;The Matrix&#x27;})\n</code></pre><p>与节点标签等效，<code>:ACTED_IN</code> 模式声明关系的类型。变量（例如，<code>role</code>）可以在语句中的其他地方使用以引用该关系。</p>\n<p>与节点属性一样，关系属性表示为括在一对大括号内的键/值对的列表，例如：<code>{roles: ['Neo']}</code>。在这种情况下，我们对角色使用了数组属性，允许指定多个角色。属性可用于存储信息和/或限制模式。</p>\n<h2>模式变量</h2>\n<p>为了提高模块化并减少重复，Cypher 允许将模式分配给变量。这允许检查匹配的路径，在其他表达式中使用等。</p>\n<pre class=\"prettyprint language-cypher\"><code>acted_in = (:Person)-[:ACTED_IN]-&gt;(:Movie)\n</code></pre><p><code>acted_in</code> 变量将包含每个找到或创建的路径的两个节点和连接关系。有许多函数可以访问路径的详细信息，例如：<code>nodes(path)</code>、<code>relationships(path)</code> 和 <code>length(path)</code>。</p>\n<h2>子句</h2>\n<p>Cypher 语句通常具有多个子句，每个子句执行一个特定任务，例如：</p>\n<ul>\n<li>在图中创建和匹配模式</li>\n<li>过滤、投影、排序或分页结果</li>\n<li>组成部分语句</li>\n</ul>\n<p>通过组合 Cypher 子句，您可以组成复杂的语句，表达您想要知道或创建的内容。</p>\n<p>有关 Cypher 子句及其使用的详细信息，请参阅 [Cypher 手册 → 子句](链接到 Cypher 手册 → 子句)。</p>\n<p>您还可以访问 [Cypher 速查表](链接到 Cypher 速查表) 以快速参考 Cypher 语法。</p>\n</div>","title":"Neo4j官方教程：第8节， 模式","last_reply_at":"2025-04-09T01:36:15.711Z","good":true,"top":false,"reply_count":0,"visit_count":3012,"create_at":"2025-04-09T01:36:15.711Z","author":{"loginname":"pangguoming","avatar_url":"https://avatars.githubusercontent.com/u/7269202?v=4&s=120"}}]}