2

这个问题有两个部分:

  1. 默认情况下,哪些 URL 协议被认为可以有效地为 Cypher 的LOAD CSV命令指定资源?

    • 到目前为止,我已经使用 http 和文件协议成功地将 CSV 文件加载到 Neo4j 中。 对这个无关问题的评论表明 ftp 也可以,但我没有尝试过,因为我没有用例。
  2. 配置非标准 URI 协议有哪些实用选项?我遇到了Neo.TransientError.Statement.ExternalResourceFailure: “指定的 URL 无效(未知协议)”。除了挖掘 Neo4j 源之外,如果主机能够使用指定的协议解析资源,是否还有修改此验证/设置的方法?

4

2 回答 2

2
  1. Neo4j 依赖于 JVM 的功能。根据https://docs.oracle.com/javase/7/docs/api/java/net/URL.html默认协议是:

    http, https, ftp, file, jar

    请注意,fileURL 是从服务器的角度解释的,而不是从客户端(一个常见的混淆来源)。

  2. 要使用自定义 URL,您需要了解 JVM 如何处理这些 URL。URL 类的javadocs解释了一种通过使用系统属性来提供自定义 URL 处理程序的方法。neo4j-wrapper.conf提供此系统属性并将包含处理程序类的 jar 文件放入文件夹中应该就足够了plugins。(注意:我自己并没有验证这种方法,但我非常有信心它会起作用)。

于 2015-05-02T09:20:26.433 回答
1

这是一个完整的示例,使用实现您自己的技术URLStreamHandler来处理resource协议。您必须将您的类命名为“Handler”,并且包名称的最后一段必须是协议名称(在本例中为resource

src/main/java/com/example/protocols/resource/Handler.java

package com.example.protocols.resource;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

public class Handler extends URLStreamHandler {
    private final ClassLoader classLoader;

    public Handler() {
        this.classLoader = getClass().getClassLoader();
    }

    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        URL resource = classLoader.getResource(url.getPath());
        if (resource == null) {
            throw new FileNotFoundException("Resource file not found: " + url.getPath());
        }
        return resource.openConnection();
    }
}

从这里开始,我们需要设置系统属性java.protocol.handler.pkgs以包含基本包com.example.protocols,以便注册协议。这可以在 Neo4j ExtensionFactory 中静态完成。由于类被 Neo4j 加载,我们知道静态块将被执行。我们还需要提供我们自己的 URLAccessRule,因为默认情况下 Neo4j 只允许使用一些选择协议。这也可能发生在 ExtensionFactory 中。

src/main/java/com/example/protocols/ProtocolInitializerFactory.java

package com.example.protocols;

import org.neo4j.annotations.service.ServiceProvider;
import org.neo4j.graphdb.security.URLAccessRule;
import org.neo4j.kernel.extension.ExtensionFactory;
import org.neo4j.kernel.extension.ExtensionType;
import org.neo4j.kernel.extension.context.ExtensionContext;
import org.neo4j.kernel.lifecycle.Lifecycle;
import org.neo4j.kernel.lifecycle.LifecycleAdapter;

@ServiceProvider
public class ProtocolInitializerFactory extends ExtensionFactory<ProtocolInitializerFactory.Dependencies> {

    private static final String PROTOCOL_HANDLER_PACKAGES = "java.protocol.handler.pkgs";

    private static final String PROTOCOL_PACKAGE = ProtocolInitializerFactory.class.getPackageName();

    static {
        String currentValue = System.getProperty(PROTOCOL_HANDLER_PACKAGES, "");
        if (currentValue.isEmpty()) {
            System.setProperty(PROTOCOL_HANDLER_PACKAGES, PROTOCOL_PACKAGE);
        } else if (!currentValue.contains(PROTOCOL_PACKAGE)) {
            System.setProperty(PROTOCOL_HANDLER_PACKAGES, currentValue + "|" + PROTOCOL_PACKAGE);
        }
    }

    public interface Dependencies {
        URLAccessRule urlAccessRule();
    }

    public ProtocolInitializerFactory() {
        super(ExtensionType.DATABASE, "ProtocolInitializer");
    }

    @Override
    public Lifecycle newInstance(ExtensionContext context, Dependencies dependencies) {
        URLAccessRule urlAccessRule = dependencies.urlAccessRule();
        return LifecycleAdapter.onInit(() -> {
            URLAccessRule customRule = (config, url) -> {
                if ("resource".equals(url.getProtocol())) { // Check the protocol name
                    return url; // Optionally, you can validate the URL here and throw an exception if it is not valid or should not be allowed access
                }
                return urlAccessRule.validate(config, url);
            };
            context.dependencySatisfier().satisfyDependency(customRule);
        });
    }
}

设置完成后,按照指南将这些类打包为 Neo4j 插件并将其放入数据库的插件目录中。

诚然,需要覆盖默认 URLAccessRule 感觉有点阴暗。最好简单地实现 URLStreamHandler,并使用另一种 CSV 加载方法,如APOC 的 apoc.load.csv。这不需要覆盖 URLAccessRule,但需要设置 Java 系统属性java.protocol.handler.pkgs

于 2020-12-16T15:55:02.697 回答