【问题标题】:neo4j huge graph and solutionneo4j 巨图及解决方案
【发布时间】:2011-10-17 14:07:09
【问题描述】:

我在 CSV 文件中有一个相当大的网络。它包含 450k 个节点和 45000000 个关系。正如我在 neo4j 文档中所读到的,这种类型的数据库可以处理如此庞大的网络。

我还了解到我可以使用嵌入式服务器以及独立服务器。

我的问题是它们之间有什么区别?我想要一个服务器来保存它的数据库状态。

第二个问题是我可以使用 REST API 对数据库执行操作,这是一个 Java API。

性能有何不同?例如,我想将所有节点级别作为输出。

是否可以从 CSV 加载图表?

我的问题的最佳解决方案是什么?

【问题讨论】:

    标签: java neo4j


    【解决方案1】:

    这是您将与 Neo4j-Batch-Inserter 一起使用以导入呼叫记录的代码,而不是动态生成数据,您当然会从文件中读取数据并相应地拆分每条记录。

    import org.apache.commons.io.FileUtils;
    import org.neo4j.graphdb.RelationshipType;
    import org.neo4j.graphdb.index.BatchInserterIndex;
    import org.neo4j.helpers.collection.MapUtil;
    import org.neo4j.index.impl.lucene.LuceneBatchInserterIndexProvider;
    import org.neo4j.kernel.impl.batchinsert.BatchInserterImpl;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    import static org.neo4j.helpers.collection.MapUtil.map;
    
    public class CallRecordImportBatch {
    
        public static final int MILLION = 1000000;
        public static final int BATCH_SIZE = MILLION;
        public static final int CALLS = 45 * MILLION;
        public static final int USERS = CALLS / 100;
        public static final File STORE_DIR = new File("target/calls_"+ CALLS);
        private static final Random rnd = new Random();
    
        enum MyRelationshipTypes implements RelationshipType {CALLED}
    
        private static String randomPhoneNumber() {
            final int phoneNumber = rnd.nextInt(USERS);
            return String.format("%013d", phoneNumber);
        }
    
        public static void main(String[] args) throws IOException {
            long time = System.currentTimeMillis();
            CallRecordImportBatch importBatch = new CallRecordImportBatch();
            importBatch.createGraphDatabase();
            System.out.println((System.currentTimeMillis() - time) + " ms: "+ "Create Database");
        }
    
        private BatchInserterImpl db;
        private BatchInserterIndex phoneNumberIndex;
    
        private void createGraphDatabase() throws IOException {
            if (STORE_DIR.exists()) FileUtils.cleanDirectory(STORE_DIR);
            STORE_DIR.mkdirs();
            db = new BatchInserterImpl(STORE_DIR.getAbsolutePath(),
                    MapUtil.stringMap("cache_type", "weak",
                            "neostore.nodestore.db.mapped_memory", "500M",
                            "neostore.relationshipstore.db.mapped_memory", "2000M",
                            "neostore.propertystore.db.mapped_memory", "1000M",
                            "neostore.propertystore.db.strings.mapped_memory", "0M",
                            "neostore.propertystore.db.arrays.mapped_memory", "0M"
                    ));
            final LuceneBatchInserterIndexProvider indexProvider = new LuceneBatchInserterIndexProvider(db);
            phoneNumberIndex = indexProvider.nodeIndex("Caller", MapUtil.stringMap("type", "exact"));
            phoneNumberIndex.setCacheCapacity("Caller", 1000000);
    
            long time = System.currentTimeMillis();
            Map<String,Long> cache = new HashMap<String,Long>(USERS);
            try {
                for (int call=0;call< CALLS;call++) {
                    if (call % BATCH_SIZE == 0) {
                        System.out.println((System.currentTimeMillis() - time) + " ms: "+ String.format("calls %d callers %d", call, cache.size()));
                        time = System.currentTimeMillis();
                    }
                    final String callerNumber = randomPhoneNumber();
                    final int duration = (int) (System.currentTimeMillis() % 3600);
                    final String calleeNumber = randomPhoneNumber();
    
                    long caller = getOrCreateCaller(cache, callerNumber);
                    long callee = getOrCreateCaller(cache, calleeNumber);
    
                    db.createRelationship(caller, callee, MyRelationshipTypes.CALLED, map("duration", duration));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println((System.currentTimeMillis() - time) + " ms: " + String.format("calls %d callers %d", CALLS, cache.size()));
            indexProvider.shutdown();
            db.shutdown();
        }
    
        private Long getOrCreateCaller(Map<String, Long> cache, String number) {
            final Long callerId = cache.get(number);
            if (callerId!=null) return callerId;
            long caller = createCaller(number);
            cache.put(number, caller);
            return caller;
        }
    
        private long createCaller(String number) {
            long caller = db.createNode(map("Number", number));
            phoneNumberIndex.add(caller, map("Number", number));
            phoneNumberIndex.flush();
            return caller;
        }
    }
    

    【讨论】:

    • 使用此代码:几行是正确的: 1 毫秒:呼叫 0 呼叫者 0 10431 毫秒:呼叫 1000000 呼叫者 444678 5651 毫秒:呼叫 2000000 呼叫者 449949 5376 毫秒:呼叫 3000000 呼叫者 449998 5652 毫秒:呼叫4000000 调用者 450000 然后:\target\calls_45000000\neostore.propertystore.db] 无法分配直接缓冲区 java.lang.OutOfMemoryError: Java heap space
    • 您可能应该使用足够的堆来运行程序以供中间用户缓存,例如-Xmx4G(取决于您的用户数)
    【解决方案2】:

    嵌入式数据库与您的应用程序位于同一进程中,这意味着没有网络开销(因此嵌入式数据库要快得多)。当然,两者都保留数据,这就是为什么你有一个数据库开始的原因:-)

    您甚至可以同时使用嵌入式模式和独立服务器,请参阅:http://docs.neo4j.org/chunked/snapshot/server-embedded.html

    要一次性加载大量数据,应使用 BatchInserter,请参阅:http://docs.neo4j.org/chunked/milestone/indexing-batchinsert.html

    【讨论】:

      【解决方案3】:

      有一个java-API 可以执行 REST 操作。

      <dependency>
          <groupId>org.neo4j</groupId>
          <artifactId>neo4j-rest-graphdb</artifactId>
          <version>1.5-SNAPSHOT</version>
      or last milestone
          <version>1.5.M02.U1</version>
      </dependency>
      

      什么意思:

      例如,我想 将所有节点级别作为输出。

      关于您的其他问题 - 您的数据模型是什么样的?

      【讨论】:

      • 我的数据模型基于呼叫详细记录。我只是得到了用户A、用户B、通话持续时间等等......在我的图形数据库中,我想在节点(用户)之间建立具有属性(连接数)的连接,并且用户需要具有属性(活动/非活动) 因为这个人可能已经退出了电信网络
      • 如何在您的文件中识别用户?用电话# ?我假设您稍后想通过电话查找以在数据库上运行查询?代码非常简单(这是一个类似的例子,我明天再发一个:gist.github.com/1375679
      猜你喜欢
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-19
      相关资源
      最近更新 更多