neo4j优化(新)

 

 

1.查询时指定具体的标签名(表名)

需要创建索引

CREATE INDEX idx_user_name FOR (p:User) ON (p.name);

MATCH (p {name: 'User_20005'}) RETURN p; ##整个图里查找,性能低
MATCH (p:User {name: 'User_20005'}) RETURN p; ##具体标签里查找,性能好 

 EXPLAIN  MATCH (p {name: 'User_20005'}) RETURN p;

 

 

EXPLAIN  MATCH (p:User {name: 'User_20005'}) RETURN p;

 

 

 

 

2.通过使用WITH子句,可以将复杂的Cypher查询拆分为多个步骤,每一步聚焦于特定的处理逻辑,从而提升可读性和优化空间

##查找朋友数量超过10的人

MATCH (p:User)-[:FRIEND_WITH]->(friend)
WITH p, count(friend) AS friendCount
WHERE friendCount > 10
RETURN p.name, friendCount;

 

3.限制返回数据:只返回需要的属性,而不是整个节点或关系

##返回整个节点(可能包含大量属性)
MATCH (p:User {name: 'User_20005'}) RETURN p;

##只返回需要的属性
MATCH (p:User {name: 'User_20005'}) RETURN p.name,p.age;

 

4.使用OPTIONAL MATCH替代OUTER JOIN模式

##查找用户及所在的公司(如果有)

MATCH (u:User {name: 'User_20005'})
OPTIONAL MATCH (u)-[:WORKS_AT]->(o:Company)
RETURN u.name, o.id



 

5.避免笛卡尔积:确保MATCH子句中的模式是连接的

##潜在笛卡尔积

MATCH (a:User), (b:Company)
WHERE a.name = 'User_20005' AND b.name = 'Company_4104'
RETURN a, b


##优化:如果有关联,明确关联

MATCH (a:User {name: 'User_20005'})-[:WORKS_AT]->(b:Company {name: 'Company_4104'})
RETURN a, b

 

 

6.优化IN操作:对于大型列表,IN操作可能较慢

##大型列表

WITH [1,2,3,4,5] AS ids
MATCH (p:User)
WHERE p.id IN ids
RETURN p



##优化:使用UNWIND和MERGE/MATCH

WITH [1,2,3,4,5] AS ids
UNWIND ids AS targetId
MATCH (p:User {id: targetId})
RETURN p

 

 

7.优化可变长度路径
在优化可变长度路径查询时,应注意控制路径的搜索范围和复杂度。
首先,建议通过限定路径的最小和最大深度(如[:REL*1..5])来减少遍历的节点和关系数量,避免无界搜索导致性能下降;

 

##1到2跳的路径
MATCH p = (a:User{name:'User_20005'})-[:WORKS_AT*1..2]->(b:Company) 
RETURN p

 

 

 

8.参数化查询

##硬编码查询
MATCH (p:Person {name: 'Alice'}) RETURN p
MATCH (p:Person {name: 'Bob'}) RETURN p

##参数化查询(效果好)
MATCH (p:Person {name: $name}) RETURN p

当使用不同的参数值(如 {name: 'Alice'} 或 {name: 'Bob'})执行参数化查询时,Neo4j 会将其视为同一个查询,只是参数不同。这样可以重用已经缓存的查询计划,显著减少每次查询时的解析和优化开销,从而提升整体性能.

 

9.查询提示(Hints)

##强制使用索引
MATCH (p:Person)
USING INDEX p:Person(name)
WHERE p.name = 'Alice'
RETURN p

##强制扫描(避免使用索引)
MATCH (p:Person)
USING SCAN p:Person
WHERE p.name = 'Alice'
RETURN p

 

 

10.造数据例子

Neo4jBulkImporter.java

 

package org.hxl.neo4j;

import org.neo4j.driver.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class Neo4jBulkImporter {
    private static final String URI = "bolt://192.168.1.135:7687";
    private static final String USER = "neo4j";
    private static final String PASSWORD = "neo4j123";
    private static final int BATCH_SIZE = 5000;
    private static final int TOTAL_USERS = 100_000;
    private static final int TOTAL_COMPANIES = 10_000;
    private static final int RELATIONS_PER_USER = 3;

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        try (Driver driver = GraphDatabase.driver(URI, AuthTokens.basic(USER, PASSWORD))) {
            // 创建唯一约束确保数据完整性
            createConstraints(driver);

            // 导入公司数据
            System.out.println("导入公司数据...");
            importCompanies(driver);

            // 导入用户数据
            System.out.println("导入用户数据...");
            importUsers(driver);

            // 创建用户关系
            System.out.println("创建用户关系...");
            createFriendships(driver);

            // 创建用户-公司关系
            System.out.println("创建用户-公司关系...");
            createEmploymentRelationships(driver);

            // 创建公司关系
            System.out.println("创建公司关系...");
            createCompanyRelationships(driver);
        }

        long endTime = System.currentTimeMillis();
        System.out.printf("\n数据导入完成! 总耗时: %.2f 秒%n", (endTime - startTime) / 1000.0);
    }

    // 创建唯一约束
    private static void createConstraints(Driver driver) {
        try (Session session = driver.session()) {
            session.run("CREATE CONSTRAINT IF NOT EXISTS FOR (u:User) REQUIRE u.id IS UNIQUE");
            session.run("CREATE CONSTRAINT IF NOT EXISTS FOR (c:Company) REQUIRE c.id IS UNIQUE");
            System.out.println("唯一约束创建成功");
        }
    }

    // 导入公司数据
    private static void importCompanies(Driver driver) {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (int offset = 0; offset < TOTAL_COMPANIES; offset += BATCH_SIZE) {
            int currentOffset = offset;
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                int currentBatchSize = Math.min(BATCH_SIZE, TOTAL_COMPANIES - currentOffset);
                try (Session session = driver.session()) {
                    String cypher = "UNWIND $batch AS row " +
                            "CREATE (c:Company {id: row.id, name: row.name, " +
                            "industry: row.industry, founded: row.founded})";
                    session.run(cypher, Values.parameters("batch",
                            generateCompanyData(currentBatchSize, currentOffset)));
                }
            }, executor);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        executor.shutdown();
        System.out.printf("成功导入 %d 家公司%n", TOTAL_COMPANIES);
    }

    // 生成公司数据
    private static List<Map<String, Object>> generateCompanyData(int size, int offset) {
        String[] industries = {"科技", "金融", "医疗", "教育", "制造", "零售", "娱乐", "能源"};
        List<Map<String, Object>> batch = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            Map<String, Object> record = new HashMap<>();
            int id = offset + i;
            record.put("id", id);
            record.put("name", "Company_" + id);
            record.put("industry", industries[id % industries.length]);
            record.put("founded", 1950 + (id % 70));
            batch.add(record);
        }
        return batch;
    }

    // 导入用户数据
    private static void importUsers(Driver driver) {
        ExecutorService executor = Executors.newFixedThreadPool(8);
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (int offset = 0; offset < TOTAL_USERS; offset += BATCH_SIZE) {
            int currentOffset = offset;
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                int currentBatchSize = Math.min(BATCH_SIZE, TOTAL_USERS - currentOffset);
                try (Session session = driver.session()) {
                    String cypher = "UNWIND $batch AS row " +
                            "CREATE (u:User {id: row.id, name: row.name, " +
                            "email: row.email, age: row.age, city: row.city})";
                    session.run(cypher, Values.parameters("batch",
                            generateUserData(currentBatchSize, currentOffset)));
                }
            }, executor);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        executor.shutdown();
        System.out.printf("成功导入 %d 位用户%n", TOTAL_USERS);
    }

    // 生成用户数据
    private static List<Map<String, Object>> generateUserData(int size, int offset) {
        String[] cities = {"北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "南京"};
        List<Map<String, Object>> batch = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            Map<String, Object> record = new HashMap<>();
            int id = offset + i;
            record.put("id", id);
            record.put("name", "User_" + id);
            record.put("email", "user" + id + "@example.com");
            record.put("age", 18 + (id % 60));
            record.put("city", cities[id % cities.length]);
            batch.add(record);
        }
        return batch;
    }

    // 创建用户之间的朋友关系
    private static void createFriendships(Driver driver) {
        ExecutorService executor = Executors.newFixedThreadPool(6);
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        int totalRelations = TOTAL_USERS * RELATIONS_PER_USER;
        int batches = (int) Math.ceil((double) totalRelations / BATCH_SIZE);

        for (int i = 0; i < batches; i++) {
            int batchIndex = i;
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try (Session session = driver.session()) {
                    String cypher = "UNWIND $batch AS row " +
                            "MATCH (u1:User {id: row.userId1}), (u2:User {id: row.userId2}) " +
                            "CREATE (u1)-[:FRIEND_WITH {since: row.since}]->(u2)";
                    session.run(cypher, Values.parameters("batch",
                            generateFriendshipData(BATCH_SIZE, batchIndex * BATCH_SIZE)));
                }
            }, executor);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        executor.shutdown();
        System.out.printf("成功创建 %d 个朋友关系%n", totalRelations);
    }

    // 生成朋友关系数据
    private static List<Map<String, Object>> generateFriendshipData(int size, int offset) {
        List<Map<String, Object>> batch = new ArrayList<>(size);
        Random random = new Random();

        for (int i = 0; i < size; i++) {
            Map<String, Object> relation = new HashMap<>();
            int user1 = random.nextInt(TOTAL_USERS);
            int user2;
            do {
                user2 = random.nextInt(TOTAL_USERS);
            } while (user1 == user2);

            relation.put("userId1", user1);
            relation.put("userId2", user2);
            relation.put("since", 2010 + random.nextInt(14));
            batch.add(relation);
        }
        return batch;
    }

    // 创建用户-公司雇佣关系
    private static void createEmploymentRelationships(Driver driver) {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        int batches = (int) Math.ceil((double) TOTAL_USERS / BATCH_SIZE);

        for (int i = 0; i < batches; i++) {
            int batchIndex = i;
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try (Session session = driver.session()) {
                    String cypher = "UNWIND $batch AS row " +
                            "MATCH (u:User {id: row.userId}), (c:Company {id: row.companyId}) " +
                            "CREATE (u)-[:WORKS_AT {position: row.position, " +
                            "startYear: row.startYear}]->(c)";
                    session.run(cypher, Values.parameters("batch",
                            generateEmploymentData(BATCH_SIZE, batchIndex * BATCH_SIZE)));
                }
            }, executor);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        executor.shutdown();
        System.out.printf("成功创建 %d 个雇佣关系%n", TOTAL_USERS);
    }

    // 生成雇佣关系数据
    private static List<Map<String, Object>> generateEmploymentData(int size, int offset) {
        String[] positions = {"工程师", "经理", "分析师", "设计师", "销售", "总监", "顾问"};
        Random random = new Random();
        List<Map<String, Object>> batch = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            int userId = offset + i;
            if (userId >= TOTAL_USERS) break;

            Map<String, Object> relation = new HashMap<>();
            relation.put("userId", userId);
            relation.put("companyId", random.nextInt(TOTAL_COMPANIES));
            relation.put("position", positions[random.nextInt(positions.length)]);
            relation.put("startYear", 2000 + random.nextInt(24));
            batch.add(relation);
        }
        return batch;
    }

    // 创建公司之间的合作关系
    private static void createCompanyRelationships(Driver driver) {
        int totalRelations = TOTAL_COMPANIES / 2;
        ExecutorService executor = Executors.newFixedThreadPool(4);
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        int batches = (int) Math.ceil((double) totalRelations / BATCH_SIZE);

        for (int i = 0; i < batches; i++) {
            int batchIndex = i;
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try (Session session = driver.session()) {
                    String cypher = "UNWIND $batch AS row " +
                            "MATCH (c1:Company {id: row.companyId1}), (c2:Company {id: row.companyId2}) " +
                            "CREATE (c1)-[:PARTNER_WITH {since: row.since, " +
                            "type: row.type}]->(c2)";
                    session.run(cypher, Values.parameters("batch",
                            generateCompanyRelationsData(BATCH_SIZE, batchIndex * BATCH_SIZE)));
                }
            }, executor);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        executor.shutdown();
        System.out.printf("成功创建 %d 个公司合作关系%n", totalRelations);
    }

    // 生成公司关系数据
    private static List<Map<String, Object>> generateCompanyRelationsData(int size, int offset) {
        String[] types = {"技术合作", "市场合作", "供应链合作", "研发合作"};
        Random random = new Random();
        List<Map<String, Object>> batch = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            Map<String, Object> relation = new HashMap<>();
            int company1 = random.nextInt(TOTAL_COMPANIES);
            int company2;
            do {
                company2 = random.nextInt(TOTAL_COMPANIES);
            } while (company1 == company2);

            relation.put("companyId1", company1);
            relation.put("companyId2", company2);
            relation.put("since", 2000 + random.nextInt(24));
            relation.put("type", types[random.nextInt(types.length)]);
            batch.add(relation);
        }
        return batch;
    }
}

 

posted @ 2025-07-09 11:17  slnngk  阅读(21)  评论(0)    收藏  举报