#1 基础用法

43 阅读11分钟

1. Cypher 查询语言基础语法

1.1 节点(Node)

  • 用圆括号 () 表示一个节点。
  • 节点可以有标签(类型),用冒号 : 标记。
  • 节点可以有属性,属性写在花括号 {} 里,类似字典。

示例:

(:Person {name:'zhangsan', age:33})

表示一个标签为 Person 的节点,属性有 nameage


1.2 关系(Relationship)

  • 用中括号 [] 表示关系。
  • 关系可以有类型,用冒号 : 标记。
  • 关系可以有属性,也写在花括号 {} 里。
  • 关系有方向,用箭头 -><- 表示。

示例:

()-[:FRIENDS {since:2020}]->()

表示一个类型为 FRIENDS 的关系,属性是 since:2020,方向从左到右。


1.3 常用操作语句

操作语法结构说明示例代码
创建节点CREATE (变量:标签 {属性})CREATE (p:Person {name:'zhangsan'})
查询节点MATCH (变量:标签 {属性}) RETURN 变量MATCH (p:Person {name:'zhangsan'}) RETURN p
创建关系MATCH 找节点,MERGE (a)-[:关系类型 {属性}]->(b)MATCH (a:Person),(b:Person) MERGE (a)-[:FRIENDS]->(b)
修改属性MATCH 找节点,SET 变量.属性=值MATCH (p:Person) SET p.age=33
删除属性MATCH 找节点,REMOVE 变量.属性MATCH (p:Person) REMOVE p.age
删除节点MATCH 找节点,DETACH DELETE 变量MATCH (p:Person) DETACH DELETE p
删除关系MATCH 找关系,DELETE 关系变量MATCH (a)-[r:FRIENDS]->(b) DELETE r

1.4 关键词说明

  • MATCH:查找已有节点或关系,相当于 SQL 的 SELECT。
  • CREATE:新建节点或关系。
  • MERGE:如果不存在则新建,已存在则不变。
  • RETURN:返回查询结果。
  • SET:设置节点或关系的属性。
  • REMOVE:删除节点或关系的属性。
  • DELETE/DETACH DELETE:删除节点或关系,DETACH DELETE 会一并删除相关关系。

2. Cypher Demo

2.1 清空数据库

MATCH (n) DETACH DELETE n

2.2 批量创建人物节点

CREATE (:Person {name:'zhangsan'}),
       (:Person {name:'lisi'}),
       (:Person {name:'wangwu'}),
       (:Person {name:'zhaoliu'}),
       (:Person {name:'sunqi'}),
       (:Person {name:'liuba'});

2.3 批量创建地区节点

CREATE (:Location {city:'Beijing', state:'BJ'}),
       (:Location {city:'Shanghai', state:'SH'}),
       (:Location {city:'Guangzhou', state:'GZ'}),
       (:Location {city:'Shenzhen', state:'SZ'}),
       (:Location {city:'Chengdu', state:'CD'});

2.4 创建人物间关系及关系属性

MATCH (a:Person {name:'zhangsan'}), (b:Person {name:'lisi'})
MERGE (a)-[:FRIENDS {since:2020}]->(b);

MATCH (a:Person {name:'wangwu'}), (b:Person {name:'zhaoliu'})
MERGE (a)-[:FRIENDS {since:2021}]->(b);

MATCH (a:Person {name:'sunqi'}), (b:Person {name:'liuba'})
MERGE (a)-[:FRIENDS {since:2019}]->(b);

MATCH (a:Person {name:'zhangsan'}), (b:Person {name:'wangwu'})
MERGE (a)-[:MARRIED {since:2015}]->(b);

2.5 创建人物与地区的关系(出生地)

MATCH (a:Person {name:'zhangsan'}), (b:Location {city:'Beijing'})
MERGE (a)-[:BORN_IN {year:1990}]->(b);

(其它人物同理)

2.6 查询示例

  • 查询所有在 Beijing 出生的人物
    MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Beijing'}) RETURN a, b;
    
  • 查询所有有外向关系的节点
    MATCH (a)-->() RETURN a;
    
  • 查询所有有关系的节点及类型
    MATCH (a)-[r]->() RETURN a.name, type(r);
    
  • 查找某人的朋友的朋友
    MATCH (a:Person {name:'zhangsan'})-[:FRIENDS]-()-[:FRIENDS]-(friend_of_a_friend)
    RETURN friend_of_a_friend.name AS fofName;
    

2.7 节点属性操作

  • 增加/修改属性
    MATCH (a:Person {name:'zhangsan'}) SET a.age=33;
    
  • 删除属性
    MATCH (a:Person {name:'zhangsan'}) REMOVE a.age;
    

2.8 删除节点及关系

  • 删除有关系的节点
    MATCH (a:Person {name:'zhangsan'})-[rel]-(b:Person) DELETE rel, a, b;
    
  • 删除所有 FRIENDS 关系
    MATCH ()-[r:FRIENDS]-() DELETE r;
    
  • 删除指定节点
    MATCH (n:Person {name:'zhangsan'}) DETACH DELETE n;
    

3. 代码 Demo

3.1 basic

package com.example.neo4jdemo.demo;

import com.example.neo4jdemo.entity.Person;
import com.example.neo4jdemo.repository.PersonRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Component;

/**
 * Cypher 操作实例 Demo
 * 演示如何使用 Spring Data Neo4j 执行各种 Cypher 操作
 *
 * 对应的 Cypher 操作示例:
 * 2.1 清空数据库
 * 2.2 批量创建人物节点
 * 2.3 批量创建地区节点
 * 2.4 创建人物间关系及关系属性
 * 2.5 创建人物与地区的关系(出生地)
 * 2.6 查询示例
 * 2.7 节点属性操作
 * 2.8 删除节点及关系
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class CypherOperationDemo implements CommandLineRunner {

    private final PersonRepository personRepository;
    private final Neo4jClient neo4jClient;

    // 是否自动执行 Demo
    private static final boolean AUTO_RUN_DEMO = false;

    @Override
    public void run(String... args) throws Exception {
        if (!AUTO_RUN_DEMO) {
            log.info("CypherOperationDemo 已禁用。如需启用,请设置 AUTO_RUN_DEMO = true");
            return;
        }

        log.info("========== Cypher 操作 Demo 开始 ==========");

        try {
            // 2.1 清空数据库
            log.info("\n>>> 2.1 清空数据库");
            clearDatabase();

            // 2.2 批量创建人物节点
            log.info("\n>>> 2.2 批量创建人物节点");
            createPersonNodes();

            // 2.3 批量创建地区节点
            log.info("\n>>> 2.3 批量创建地区节点");
            createLocationNodes();

            // 2.4 创建人物间关系及关系属性
            log.info("\n>>> 2.4 创建人物间关系及关系属性");
            createPersonRelationships();

            // 2.5 创建人物与地区的关系(出生地)
            log.info("\n>>> 2.5 创建人物与地区的关系(出生地)");
            createBornInRelationships();

            // 2.6 查询示例
            log.info("\n>>> 2.6 查询示例");
            queryExamples();

            // 2.7 节点属性操作
            log.info("\n>>> 2.7 节点属性操作");
            nodePropertyOperations();

            // 2.8 删除节点及关系
            log.info("\n>>> 2.8 删除节点及关系");
            deleteOperations();

            log.info("\n========== Cypher 操作 Demo 完成 ==========");
        } catch (Exception e) {
            log.error("Demo 执行失败", e);
            throw e;
        }
    }

    /**
     * 2.1 清空数据库
     * Cypher: MATCH (n) DETACH DELETE n
     */
    private void clearDatabase() {
        log.info("执行: MATCH (n) DETACH DELETE n");
        neo4jClient.query("MATCH (n) DETACH DELETE n")
                .run();
        log.info("✓ 数据库已清空");
    }

    /**
     * 2.2 批量创建人物节点
     * Cypher:
     * CREATE (:Person {name:'zhangsan'}),
     *        (:Person {name:'lisi'}),
     *        (:Person {name:'wangwu'}),
     *        (:Person {name:'zhaoliu'}),
     *        (:Person {name:'sunqi'}),
     *        (:Person {name:'liuba'});
     */
    private void createPersonNodes() {
        String[] names = {"zhangsan", "lisi", "wangwu", "zhaoliu", "sunqi", "liuba"};

        // 方式1: 使用 Repository 逐个保存
        log.info("方式1: 使用 Repository 逐个保存");
        for (String name : names) {
            Person person = new Person(name, null);
            personRepository.save(person);
            log.info("  创建人物: {}", name);
        }

        // 方式2: 使用 Neo4jClient 执行 Cypher 批量创建(更高效)
        log.info("方式2: 使用 Neo4jClient 执行 Cypher 批量创建");
        String cypherQuery = "CREATE (:Person {name:'zhangsan'})," +
                "       (:Person {name:'lisi'})," +
                "       (:Person {name:'wangwu'})," +
                "       (:Person {name:'zhaoliu'})," +
                "       (:Person {name:'sunqi'})," +
                "       (:Person {name:'liuba'})";
        neo4jClient.query(cypherQuery).run();
        log.info("✓ 人物节点创建完成");
    }

    /**
     * 2.3 批量创建地区节点
     * Cypher:
     * CREATE (:Location {city:'Beijing', state:'BJ'}),
     *        (:Location {city:'Shanghai', state:'SH'}),
     *        (:Location {city:'Guangzhou', state:'GZ'}),
     *        (:Location {city:'Shenzhen', state:'SZ'}),
     *        (:Location {city:'Chengdu', state:'CD'});
     */
    private void createLocationNodes() {
        log.info("执行: CREATE (:Location {...}) 批量创建地区节点");
        String cypherQuery = "CREATE (:Location {city:'Beijing', state:'BJ'})," +
                "       (:Location {city:'Shanghai', state:'SH'})," +
                "       (:Location {city:'Guangzhou', state:'GZ'})," +
                "       (:Location {city:'Shenzhen', state:'SZ'})," +
                "       (:Location {city:'Chengdu', state:'CD'})";
        neo4jClient.query(cypherQuery).run();
        log.info("✓ 地区节点创建完成");
    }

    /**
     * 2.4 创建人物间关系及关系属性
     * Cypher:
     * MATCH (a:Person {name:'zhangsan'}), (b:Person {name:'lisi'})
     * MERGE (a)-[:FRIENDS {since:2020}]->(b);
     * ... 其他关系
     */
    private void createPersonRelationships() {
        // 关系定义: [源人物, 目标人物, 关系类型, 关系属性]
        Object[][] relationships = {
                {"zhangsan", "lisi", "FRIENDS", 2020},
                {"wangwu", "zhaoliu", "FRIENDS", 2021},
                {"sunqi", "liuba", "FRIENDS", 2019},
                {"zhangsan", "wangwu", "MARRIED", 2015}
        };

        for (Object[] rel : relationships) {
            String personA = (String) rel[0];
            String personB = (String) rel[1];
            String relType = (String) rel[2];
            Integer year = (Integer) rel[3];

            String cypherQuery = String.format(
                    "MATCH (a:Person {name:'%s'}), (b:Person {name:'%s'}) " +
                    "MERGE (a)-[:%s {since:%d}]->(b)",
                    personA, personB, relType, year
            );
            neo4jClient.query(cypherQuery).run();
            log.info("  创建关系: {} -[{}]-> {} (since: {})", personA, relType, personB, year);
        }
        log.info("✓ 人物间关系创建完成");
    }

    /**
     * 2.5 创建人物与地区的关系(出生地)
     * Cypher:
     * MATCH (a:Person {name:'zhangsan'}), (b:Location {city:'Beijing'})
     * MERGE (a)-[:BORN_IN {year:1990}]->(b);
     */
    private void createBornInRelationships() {
        // 人物与出生地的映射
        Object[][] bornInData = {
                {"zhangsan", "Beijing", 1990},
                {"lisi", "Shanghai", 1992},
                {"wangwu", "Guangzhou", 1988},
                {"zhaoliu", "Shenzhen", 1995},
                {"sunqi", "Chengdu", 1991},
                {"liuba", "Beijing", 1993}
        };

        for (Object[] data : bornInData) {
            String personName = (String) data[0];
            String city = (String) data[1];
            Integer year = (Integer) data[2];

            String cypherQuery = String.format(
                    "MATCH (a:Person {name:'%s'}), (b:Location {city:'%s'}) " +
                    "MERGE (a)-[:BORN_IN {year:%d}]->(b)",
                    personName, city, year
            );
            neo4jClient.query(cypherQuery).run();
            log.info("  创建关系: {} -[BORN_IN]-> {} (year: {})", personName, city, year);
        }
        log.info("✓ 出生地关系创建完成");
    }

    /**
     * 2.6 查询示例
     */
    private void queryExamples() {
        // 查询1: 查询所有在 Beijing 出生的人物
        log.info("\n查询1: 查询所有在 Beijing 出生的人物");
        log.info("Cypher: MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Beijing'}) RETURN a, b");
        String query1 = "MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Beijing'}) RETURN a.name as name, b.city as city";
        neo4jClient.query(query1)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("  {} 出生于 {}", record.get("name"), record.get("city"));
                });

        // 查询2: 查询所有有外向关系的节点
        log.info("\n查询2: 查询所有有外向关系的节点");
        log.info("Cypher: MATCH (a)-->() RETURN a");
        String query2 = "MATCH (a)-->() RETURN DISTINCT a.name as name";
        neo4jClient.query(query2)
                .fetch()
                .all()
                .forEach(record -> {
                    Object name = record.get("name");
                    if (name != null) {
                        log.info("  {}", name);
                    }
                });

        // 查询3: 查询所有有关系的节点及类型
        log.info("\n查询3: 查询所有有关系的节点及类型");
        log.info("Cypher: MATCH (a)-[r]->() RETURN a.name, type(r)");
        String query3 = "MATCH (a)-[r]->() RETURN a.name as name, type(r) as relType";
        neo4jClient.query(query3)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("  {} -[{}]->", record.get("name"), record.get("relType"));
                });

        // 查询4: 查找某人的朋友的朋友
        log.info("\n查询4: 查找 zhangsan 的朋友的朋友");
        log.info("Cypher: MATCH (a:Person {name:'zhangsan'})-[:FRIENDS]-()-[:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name");
        String query4 = "MATCH (a:Person {name:'zhangsan'})-[:FRIENDS]-()-[:FRIENDS]-(fof) RETURN DISTINCT fof.name as fofName";
        neo4jClient.query(query4)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("  朋友的朋友: {}", record.get("fofName"));
                });
    }

    /**
     * 2.7 节点属性操作
     */
    private void nodePropertyOperations() {
        // 增加/修改属性
        log.info("\n增加/修改属性");
        log.info("Cypher: MATCH (a:Person {name:'zhangsan'}) SET a.age=33");
        String updateQuery = "MATCH (a:Person {name:'zhangsan'}) SET a.age=33";
        neo4jClient.query(updateQuery).run();
        log.info("✓ 已设置 zhangsan 的年龄为 33");

        // 查询验证
        String verifyQuery = "MATCH (a:Person {name:'zhangsan'}) RETURN a.age as age";
        neo4jClient.query(verifyQuery)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("  验证: zhangsan 的年龄 = {}", record.get("age"));
                });

        // 删除属性
        log.info("\n删除属性");
        log.info("Cypher: MATCH (a:Person {name:'zhangsan'}) REMOVE a.age");
        String removeQuery = "MATCH (a:Person {name:'zhangsan'}) REMOVE a.age";
        neo4jClient.query(removeQuery).run();
        log.info("✓ 已删除 zhangsan 的年龄属性");
    }

    /**
     * 2.8 删除节点及关系
     */
    private void deleteOperations() {
        // 删除有关系的节点
        log.info("\n删除有关系的节点");
        log.info("Cypher: MATCH (a:Person {name:'zhangsan'})-[rel]-(b:Person) DELETE rel, a, b");
        String deleteWithRelQuery = "MATCH (a:Person {name:'zhangsan'})-[rel]-(b:Person) DELETE rel, a, b";
        neo4jClient.query(deleteWithRelQuery).run();
        log.info("✓ 已删除 zhangsan 及其关系");

        // 删除所有 FRIENDS 关系
        log.info("\n删除所有 FRIENDS 关系");
        log.info("Cypher: MATCH ()-[r:FRIENDS]-() DELETE r");
        String deleteFriendsQuery = "MATCH ()-[r:FRIENDS]-() DELETE r";
        neo4jClient.query(deleteFriendsQuery).run();
        log.info("✓ 已删除所有 FRIENDS 关系");

        // 删除指定节点
        log.info("\n删除指定节点");
        log.info("Cypher: MATCH (n:Person {name:'lisi'}) DETACH DELETE n");
        String deleteNodeQuery = "MATCH (n:Person {name:'lisi'}) DETACH DELETE n";
        neo4jClient.query(deleteNodeQuery).run();
        log.info("✓ 已删除 lisi 节点");

        // 统计剩余节点
        log.info("\n统计剩余节点");
        String countQuery = "MATCH (n:Person) RETURN count(n) as count";
        neo4jClient.query(countQuery)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("  剩余 Person 节点数: {}", record.get("count"));
                });
    }
}

3.2 advanced

package com.example.neo4jdemo.demo;

import com.example.neo4jdemo.entity.Location;
import com.example.neo4jdemo.entity.Person;
import com.example.neo4jdemo.repository.LocationRepository;
import com.example.neo4jdemo.repository.PersonRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 高级 Cypher 操作 Demo
 * 演示参数化查询、事务管理、复杂查询等高级用法
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class AdvancedCypherDemo {

    private final Neo4jClient neo4jClient;
    private final PersonRepository personRepository;
    private final LocationRepository locationRepository;

    /**
     * 示例1: 参数化查询(防止 Cypher 注入)
     */
    public void parameterizedQueryExample() {
        log.info("\n========== 示例1: 参数化查询 ==========");

        String name = "zhangsan";
        Integer minAge = 25;

        // ✅ 推荐: 使用参数化查询
        String query = "MATCH (p:Person {name:$name}) WHERE p.age > $minAge RETURN p";
        neo4jClient.query(query)
                .bind(name).to("name")
                .bind(minAge).to("minAge")
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("找到人物: {}", record.get("p"));
                });

        log.info("✓ 参数化查询完成");
    }

    /**
     * 示例2: 复杂查询 - 查找共同朋友
     * 查找两个人的共同朋友
     */
    public void findCommonFriendsExample() {
        log.info("\n========== 示例2: 查找共同朋友 ==========");

        String person1 = "zhangsan";
        String person2 = "lisi";

        String query = "MATCH (p1:Person {name:$person1})-[:FRIENDS]-(friend), " +
                "(p2:Person {name:$person2})-[:FRIENDS]-(friend) " +
                "RETURN DISTINCT friend.name as commonFriend";

        neo4jClient.query(query)
                .bind(person1).to("person1")
                .bind(person2).to("person2")
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("共同朋友: {}", record.get("commonFriend"));
                });

        log.info("✓ 共同朋友查询完成");
    }

    /**
     * 示例3: 聚合查询 - 统计信息
     */
    public void aggregationQueryExample() {
        log.info("\n========== 示例3: 聚合查询 ==========");

        // 统计总人数
        String countQuery = "MATCH (p:Person) RETURN count(p) as totalPeople";
        neo4jClient.query(countQuery)
                .fetch()
                .one()
                .ifPresent(record -> {
                    log.info("总人数: {}", record.get("totalPeople"));
                });

        // 统计每个城市的人数
        String cityCountQuery = "MATCH (p:Person)-[:BORN_IN]->(l:Location) " +
                "RETURN l.city as city, count(p) as count " +
                "ORDER BY count DESC";
        neo4jClient.query(cityCountQuery)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("城市: {}, 人数: {}", record.get("city"), record.get("count"));
                });

        log.info("✓ 聚合查询完成");
    }

    /**
     * 示例4: 路径查询 - 查找最短路径
     */
    public void pathQueryExample() {
        log.info("\n========== 示例4: 路径查询 ==========");

        String startPerson = "zhangsan";
        String endPerson = "liuba";

        // 查找两个人之间的所有路径(最多3跳)
        String pathQuery = "MATCH path = (p1:Person {name:$start})-[*1..3]-(p2:Person {name:$end}) " +
                "RETURN path, length(path) as pathLength";

        neo4jClient.query(pathQuery)
                .bind(startPerson).to("start")
                .bind(endPerson).to("end")
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("找到路径,长度: {}", record.get("pathLength"));
                });

        log.info("✓ 路径查询完成");
    }

    /**
     * 示例5: 条件更新 - 批量更新属性
     */
    public void conditionalUpdateExample() {
        log.info("\n========== 示例5: 条件更新 ==========");

        Integer ageThreshold = 30;
        String city = "Beijing";

        // 更新所有在 Beijing 出生且年龄超过 30 的人的属性
        String updateQuery = "MATCH (p:Person)-[:BORN_IN]->(l:Location {city:$city}) " +
                "WHERE p.age > $ageThreshold " +
                "SET p.vip = true " +
                "RETURN p.name as name";

        neo4jClient.query(updateQuery)
                .bind(city).to("city")
                .bind(ageThreshold).to("ageThreshold")
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("已更新: {}", record.get("name"));
                });

        log.info("✓ 条件更新完成");
    }

    /**
     * 示例6: 事务管理 - 创建人物及其关系
     */
    @Transactional
    public void transactionalOperationExample() {
        log.info("\n========== 示例6: 事务管理 ==========");

        try {
            // 创建新人物
            Person newPerson = new Person("xiaoming", 28);
            personRepository.save(newPerson);
            log.info("✓ 创建人物: xiaoming");

            // 创建新地区
            Location newLocation = new Location("Hangzhou", "HZ");
            locationRepository.save(newLocation);
            log.info("✓ 创建地区: Hangzhou");

            // 创建关系
            String relationQuery = "MATCH (p:Person {name:'xiaoming'}), (l:Location {city:'Hangzhou'}) " +
                    "MERGE (p)-[:BORN_IN {year:1996}]->(l)";
            neo4jClient.query(relationQuery).run();
            log.info("✓ 创建关系: xiaoming -[BORN_IN]-> Hangzhou");

            log.info("✓ 事务操作完成(全部成功)");
        } catch (Exception e) {
            log.error("事务操作失败,将自动回滚", e);
            throw e;
        }
    }

    /**
     * 示例7: 返回多种数据类型
     */
    public void multipleReturnTypesExample() {
        log.info("\n========== 示例7: 返回多种数据类型 ==========");

        String query = "MATCH (p:Person)-[r:FRIENDS]->(friend) " +
                "RETURN p.name as personName, " +
                "       friend.name as friendName, " +
                "       r.since as since, " +
                "       p.age as age, " +
                "       p.vip as isVip";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    String personName = (String) record.get("personName");
                    String friendName = (String) record.get("friendName");
                    Integer since = (Integer) record.get("since");
                    Integer age = (Integer) record.get("age");
                    Boolean isVip = (Boolean) record.get("isVip");

                    log.info("人物: {}, 年龄: {}, VIP: {}, 朋友: {}, 关系始于: {}",
                            personName, age, isVip, friendName, since);
                });

        log.info("✓ 多类型返回查询完成");
    }

    /**
     * 示例8: 使用 CASE 语句
     */
    public void caseStatementExample() {
        log.info("\n========== 示例8: CASE 语句 ==========");

        String query = "MATCH (p:Person) " +
                "RETURN p.name as name, " +
                "       CASE " +
                "           WHEN p.age < 25 THEN '年轻' " +
                "           WHEN p.age < 35 THEN '中年' " +
                "           ELSE '年长' " +
                "       END as ageGroup";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("人物: {}, 年龄组: {}", record.get("name"), record.get("ageGroup"));
                });

        log.info("✓ CASE 语句查询完成");
    }

    /**
     * 示例9: 使用 COLLECT 聚合
     */
    public void collectAggregationExample() {
        log.info("\n========== 示例9: COLLECT 聚合 ==========");

        String query = "MATCH (p:Person)-[:FRIENDS]->(friend) " +
                "RETURN p.name as person, collect(friend.name) as friends";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    String person = (String) record.get("person");
                    List<?> friends = (List<?>) record.get("friends");
                    log.info("人物: {}, 朋友列表: {}", person, friends);
                });

        log.info("✓ COLLECT 聚合查询完成");
    }

    /**
     * 示例10: 使用 APOC 函数(如果已安装)
     * 计算两个节点之间的最短路径长度
     */
    public void shortestPathExample() {
        log.info("\n========== 示例10: 最短路径 ==========");

        String person1 = "zhangsan";
        String person2 = "liuba";

        // 使用 Cypher 的 shortestPath 函数
        String query = "MATCH (p1:Person {name:$person1}), (p2:Person {name:$person2}) " +
                "MATCH path = shortestPath((p1)-[*]-(p2)) " +
                "RETURN length(path) as distance";

        neo4jClient.query(query)
                .bind(person1).to("person1")
                .bind(person2).to("person2")
                .fetch()
                .one()
                .ifPresent(record -> {
                    log.info("最短路径距离: {}", record.get("distance"));
                });

        log.info("✓ 最短路径查询完成");
    }

    /**
     * 示例11: 批量删除操作
     */
    public void batchDeleteExample() {
        log.info("\n========== 示例11: 批量删除 ==========");

        // 删除所有年龄小于 20 的人
        String deleteQuery = "MATCH (p:Person) WHERE p.age < $minAge " +
                "DETACH DELETE p " +
                "RETURN count(p) as deletedCount";

        neo4jClient.query(deleteQuery)
                .bind(20).to("minAge")
                .fetch()
                .one()
                .ifPresent(record -> {
                    log.info("已删除 {} 个人物", record.get("deletedCount"));
                });

        log.info("✓ 批量删除完成");
    }

    /**
     * 示例12: 使用 DISTINCT 去重
     */
    public void distinctExample() {
        log.info("\n========== 示例12: DISTINCT 去重 ==========");

        String query = "MATCH (p:Person)-[:BORN_IN]->(l:Location) " +
                "RETURN DISTINCT l.city as city";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("城市: {}", record.get("city"));
                });

        log.info("✓ DISTINCT 查询完成");
    }

    /**
     * 示例13: 使用 ORDER BY 和 LIMIT
     */
    public void orderByLimitExample() {
        log.info("\n========== 示例13: ORDER BY 和 LIMIT ==========");

        String query = "MATCH (p:Person) " +
                "RETURN p.name as name, p.age as age " +
                "ORDER BY p.age DESC " +
                "LIMIT 5";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("人物: {}, 年龄: {}", record.get("name"), record.get("age"));
                });

        log.info("✓ ORDER BY LIMIT 查询完成");
    }

    /**
     * 示例14: 使用 SKIP 和 LIMIT 进行分页
     */
    public void paginationExample() {
        log.info("\n========== 示例14: 分页查询 ==========");

        int pageSize = 3;
        int pageNumber = 1;
        int skip = (pageNumber - 1) * pageSize;

        String query = "MATCH (p:Person) " +
                "RETURN p.name as name, p.age as age " +
                "ORDER BY p.name " +
                "SKIP $skip LIMIT $limit";

        neo4jClient.query(query)
                .bind(skip).to("skip")
                .bind(pageSize).to("limit")
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("人物: {}, 年龄: {}", record.get("name"), record.get("age"));
                });

        log.info("✓ 分页查询完成");
    }

    /**
     * 示例15: 使用 WITH 进行多步查询
     */
    public void multiStepQueryExample() {
        log.info("\n========== 示例15: 多步查询 ==========");

        String query = "MATCH (p:Person)-[:FRIENDS]->(friend) " +
                "WITH p, count(friend) as friendCount " +
                "WHERE friendCount > 1 " +
                "RETURN p.name as name, friendCount";

        neo4jClient.query(query)
                .fetch()
                .all()
                .forEach(record -> {
                    log.info("人物: {}, 朋友数: {}", record.get("name"), record.get("friendCount"));
                });

        log.info("✓ 多步查询完成");
    }
}