加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

Discourse users Discord

Awesome Procedures for Neo4j 4.4.x

Introduction

apoc

Neo4j 3.x introduced the concept of user-defined procedures and functions. Those are custom implementations of certain functionality, that can’t be (easily) expressed in Cypher itself. They are implemented in Java and can be easily deployed into your Neo4j instance, and then be called from Cypher directly.

The APOC library consists of many (about 450) procedures and functions to help with many different tasks in areas like data integration, graph algorithms or data conversion.

License

Apache License 2.0

"APOC" Name history

Apoc was the technician and driver on board of the Nebuchadnezzar in the Matrix movie. He was killed by Cypher.

APOC was also the first bundled A Package Of Component for Neo4j in 2009.

APOC also stands for "Awesome Procedures On Cypher"

Installation: With Neo4j Desktop

APOC Full can be installed with Neo4j Desktop, after creating your database, by going to the Manage screen, and then the Plugins tab. Click Install in the APOC box and wait until you see a green check mark near "APOC".

desktop apoc

Feedback

Please provide feedback and report bugs as GitHub issues or join the Neo4j Community Forum and ask with the APOC tag.

Calling Procedures & Functions within Cypher

User defined Functions can be used in any expression or predicate, just like built-in functions.

Procedures can be called stand-alone with CALL procedure.name();

But you can also integrate them into your Cypher statements which makes them so much more powerful.

Load JSON example
WITH 'https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/4.4/core/src/test/resources/person.json' AS url

CALL apoc.load.json(url) YIELD value as person

MERGE (p:Person {name:person.name})
   ON CREATE SET p.age = person.age, p.children = size(person.children)

APOC Procedures & Functions Overview

All included procedures are listed in the overview in the documentation and detailed in subsequent sections.

Built in Help

apoc help apoc

call apoc.help('keyword')

lists name, description, signature, roles, based on keyword

Detailed Feature Documentation

See the APOC User Guide for documentation of each of the major features of the library, including data import/export, graph refactoring, data conversion, and more.

Procedure & Function Signatures

To call procedures correctly, you need to know their parameter names, types and positions. And for YIELDing their results, you have to know the output column names and types.

INFO:The signatures are shown in error messages, if you use a procedure incorrectly.

You can see the procedures signature in the output of CALL apoc.help("name")

CALL apoc.help("dijkstra")

The signature is always name : : TYPE, so in this case:

apoc.algo.dijkstra
 (startNode :: NODE?, endNode :: NODE?,
   relationshipTypesAndDirections :: STRING?, weightPropertyName :: STRING?)
:: (path :: PATH?, weight :: FLOAT?)
Table 1. Parameter Explanation
Name Type

Procedure Parameters

startNode

Node

endNode

Node

relationshipTypesAndDirections

String

weightPropertyName

String

Output Return Columns

path

Path

weight

Float

Manual Installation: Download latest release

Since APOC relies on Neo4j’s internal APIs you need to use the matching APOC version for your Neo4j installaton. Make sure that the first two version numbers match between Neo4j and APOC.

Go to the latest release for Neo4j version 4.4 and download the binary jar to place into your $NEO4J_HOME/plugins folder.

You can find all releases here.

Manual Configuration

Warning

For security reasons, procedures and functions that use internal APIs are disabled by default. Loading and enabling APOC procedures and functions can be configured using the Neo4j config file. For more details, see the APOC installation documentation.

Version Compatibility Matrix

Since APOC relies in some places on Neo4j’s internal APIs you need to use the right APOC version for your Neo4j installaton.

APOC uses a consistent versioning scheme: <neo4j-version>.<apoc> version. The trailing <apoc> part of the version number will be incremented with every apoc release.

apoc version neo4j version

4.4.0.1

4.4.0 (4.3.x)

4.3.0.4

4.3.7 (4.3.x)

4.2.0.9

4.2.11 (4.2.x)

4.1.0.10

4.1.11 (4.1.x)

4.0.0.18

4.0.12 (4.0.x)

3.5.0.15

3.5.30 (3.5.x)

3.4.0.8

3.4.18 (3.4.x)

3.3.0.4

3.3.9 (3.3.x)

3.2.3.6

3.2.14 (3.2.x)

3.1.3.9

3.1.9 (3.1.x)

3.0.8.6

3.0.12 (3.0.x)

3.5.0.0

3.5.0-beta01

3.4.0.2

3.4.5

3.3.0.3

3.3.5

3.2.3.5

3.2.3

3.1.3.8

3.1.5

Get APOC Version

To know your current apoc version you can use the function :

RETURN apoc.version();

Using APOC with the Neo4j Docker image

APOC Full can be used with the Neo4j Docker image via the NEO4JLABS_PLUGINS environment variable. If we use this environment variable, the APOC plugin will be downloaded and configured at runtime.

Note

This feature is intended to facilitate using APOC in development environments, but it is not recommended for use in production environments.

The following runs Neo4j 4.0 in a Docker container with the latest version of the APOC Library
docker run \
    -p 7474:7474 -p 7687:7687 \
    -v $PWD/data:/data -v $PWD/plugins:/plugins \
    --name neo4j-apoc \
    -e NEO4J_apoc_export_file_enabled=true \
    -e NEO4J_apoc_import_file_enabled=true \
    -e NEO4J_apoc_import_file_use__neo4j__config=true \
    -e NEO4JLABS_PLUGINS=\[\"apoc\"\] \
    neo4j:4.0

We should see the following two lines in the output after running this command:

Fetching versions.json for Plugin 'apoc' from https://neo4j-contrib.github.io/neo4j-apoc-procedures/versions.json
Installing Plugin 'apoc' from https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/4.4.0.30/4.4.0.30-all.jar to /plugins/apoc.jar

In a production environment we should download the APOC release matching our Neo4j version and, copy it to a local folder, and supply it as a data volume mounted at /plugins.

The following downloads the APOC Library into the plugins directory and then mounts that folder to the Neo4j Docker container
mkdir plugins
pushd plugins
wget https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/4.4.0.30/apoc-4.4.0.30-all.jar
popd
docker run --rm -e NEO4J_AUTH=none -p 7474:7474 -v $PWD/plugins:/plugins -p 7687:7687 neo4j:4.4

If you want to pass custom apoc config to your Docker instance, you can use environment variables, like here:

docker run \
    -p 7474:7474 -p 7687:7687 \
    -v $PWD/data:/data -v $PWD/plugins:/plugins \
    --name neo4j-apoc \
    -e NEO4J_apoc_export_file_enabled=true \
    -e NEO4J_apoc_import_file_enabled=true \
    -e NEO4J_apoc_import_file_use__neo4j__config=true \
    neo4j

Build & install the current development branch from source

git clone https://github.com/neo4j-contrib/neo4j-apoc-procedures
cd neo4j-apoc-procedures
./gradlew shadow
cp build/full/libs/apoc-<version>-all.jar $NEO4J_HOME/plugins/
$NEO4J_HOME/bin/neo4j restart

A full build including running the tests can be run by ./gradlew build.

Applying Code-style

./gradlew spotlessApply

To apply the spotless code-style, run the above gradle command, this will remove all unused imports

// All licenses that we accept, and their aliases def allowList = [ [name: 'BSD-2-Clause', url: 'http://opensource.org/licenses/BSD-2-Clause', aliases: [ [name: 'BSD-style', url: 'http://www.opensource.org/licenses/bsd-license.php'], [name: 'BSD', url: 'http://www.opensource.org/licenses/bsd-license.php'], [name: 'The BSD License', url: 'http://www.opensource.org/licenses/bsd-license.php'], [name: 'BSD 2-Clause License'], [name: 'BSD 2-Clause license', url: 'http://opensource.org/licenses/BSD-2-Clause'], [name: 'BSD', url: 'http://www.jcraft.com/jzlib/LICENSE.txt'], [name: 'Revised BSD', url: 'http://www.jcraft.com/jsch/LICENSE.txt'], ]], [name: 'BSD-3-Clause', url: 'http://opensource.org/licenses/BSD-3-Clause', aliases: [ [name: 'BSD-3-Clause', url: 'https://asm.ow2.io/license.html'], [name: 'The BSD 3-Clause License'], [name: 'The 3-Clause BSD License'], [name: '3-Clause BSD License'], [name: 'BSD 3-Clause'], [name: 'BSD 3 Clause'], [name: 'BSD 3-clause'], [name: 'BSD 3-Clause License'], [name: 'BSD Licence 3'], [name: 'BSD License 3'], [name: 'New BSD License'], [name: 'New BSD license'], [name: 'The New BSD License'], [name: 'BSD License', url: 'http://www.antlr.org/license.html'], [name: 'BSD licence', url: 'http://antlr.org/license.html'], [name: 'The BSD License', url: 'http://www.antlr.org/license.html'], [name: 'BSD', url: 'http://asm.ow2.org/license.html'], [name: 'BSD', url: 'http://www.jcraft.com/jsch/LICENSE.txt'], [name: 'BSD', url: 'https://github.com/sbt/test-interface/blob/master/LICENSE'], [name: 'BSD', url: 'LICENSE.txt'], [name: 'BSD 3-Clause "New" or "Revised" License (BSD-3-Clause)'], [name: '', url: 'http://asm.ow2.org/license.html'], [name: 'BSD', url: 'http://asm.objectweb.org/license.html'], ]], [name: 'Apache-2.0', url: 'https://opensource.org/licenses/Apache-2.0', aliases: [ [name: 'The Apache Software License, Version 2.0'], [name: 'The Apache License, Version 2.0'], [name: 'The Apache Software License, version 2.0'], [name: 'Apache 2'], [name: 'Apache v2'], [name: 'Apache License, Version 2.0'], [name: 'Apache License, Version 2'], [name: 'Apache Software License - Version 2.0'], [name: 'Apache License 2.0'], [name: 'Apache License'], [name: 'Apache 2.0'], [name: 'Apache-2.0'], [name: 'Apache 2.0 License'], [name: 'ASL'], [name: 'ASL 2.0'], [name: 'the Apache License, ASL Version 2.0'], [name: 'Apache License V2.0'], [name: 'Apache License v2.0'], [name: 'Apache License Version 2.0'], [name: '', url: 'http://www.apache.org/licenses/LICENSE-2.0.txt'], ]], [name: 'MIT', url: 'https://opensource.org/licenses/MIT', aliases: [ [name: 'MIT'], [name: 'MIT license'], [name: 'MIT License'], [name: 'The MIT License'], [name: 'Bouncy Castle Licence'], [name: 'MIT-0', url: 'https://spdx.org/licenses/MIT-0.html'], ]], [name: 'Eclipse Distribution License - v 1.0', url: 'https://www.eclipse.org/licenses/edl-v10.html', aliases: [ [name: 'Eclipse Distribution License - v 1.0', url: 'http://www.eclipse.org/org/documents/edl-v10.php'], [name: 'EDL 1.0'], ]], [name: 'Eclipse Public License - v 1.0', url: 'https://www.eclipse.org/legal/epl-v10.html', aliases: [ [name: 'Eclipse Public License 1.0'], [name: 'EPL', url: 'http://www.eclipse.org/legal/epl-v10.html'] ]], [name: 'Eclipse Public License - v 2.0', url: 'http://www.eclipse.org/legal/epl-2.0.html', aliases: [ [name: 'Eclipse Public License 2.0'], [name: 'Eclipse Public License v2.0', url: 'https://www.eclipse.org/legal/epl-v20.html'], [name: 'EPL 2.0', url: 'http://www.eclipse.org/legal/epl-2.0'], [name: 'Eclipse Public License - v 2.0', url: 'https://www.eclipse.org/legal/epl-v20.html'] ]], [name: 'GNU General Public License (GPL), version 2, with the Classpath exception', url: 'http://openjdk.java.net/legal/gplv2+ce.html', aliases: [ [name: 'GPL-2.0'], [name: 'GPL'], [name: 'GNU General Public License Version 2', url: 'http://www.gnu.org/copyleft/gpl.html'] ]], [name: 'GNU LESSER GENERAL PUBLIC LICENSE, Version 2.1', url: 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html'], [name: 'Public Domain, per Creative Commons CC0', url: 'http://creativecommons.org/publicdomain/zero/1.0/', aliases: [ [name: 'CC0'], [name: 'Public Domain'], ]], [name: 'MPL-2.0', url: 'https://www.mozilla.org/MPL/2.0/', aliases: [ [name: 'Mozilla Public License Version 2.0'], [name: 'Mozilla Public License, v. 2.0', url: 'http://mozilla.org/MPL/2.0/'], ]], [name: 'Common Development and Distribution License Version 1.0', aliases: [ [name: 'COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0'] ]], [name: 'Common Development and Distribution License Version 1.1', aliases: [ [name: 'CDDL1.1'], [name: 'CDDL 1.1'], [name: 'Common Development and Distribution License (CDDL), Version 1.1'], [name: 'CDDL License', url: 'http://www.opensource.org/licenses/cddl1.php'] ]], [name: 'Common Development and Distribution License Version 1.1 and GNU General Public License, version 2 with the Classpath Exception', aliases: [ [name: 'CDDL1.1-GPL2/CPE'], [name: 'Dual license consisting of the CDDL v1.1 and GPL v2'], [name: 'CDDL + GPLv2 with classpath exception'], ]], [name: 'The Go license', url: 'https://golang.org/LICENSE'], [name: 'The OpenLDAP Public License', url: 'http://www.openldap.org/software/release/license.html'], ] // Dependency license reporting downloadLicenses { dependencyConfiguration = 'runtimeClasspath' // Add licenses to some libraries which don't declare their license inside the POM. Should be rechecked if the version is updated. licenses = [ 'javax.servlet.jsp:jsp-api:2.1' : license('Common Development and Distribution License Version 1.1', null), 'org.antlr:ST4:4.1' : license('BSD-3-Clause', null), 'org.gradle:gradle-tooling-api:6.1.1' : license('Apache-2.0', null), 'org.jline:jline:3.22.0' : license('BSD-2-Clause', 'http://opensource.org/licenses/BSD-2-Clause'), 'com.sun.codemodel:codemodel:2.6' : license('Common Development and Distribution License Version 1.1', null), ] aliases = allowList.collectEntries { lic -> def actual = license(lic.name, lic.url) def alternatives = lic.aliases.collect { it.url ? license(it.name, it.url) : it.name } [(actual): alternatives] } } tasks.downloadLicenses.ext.licenseToDependencyJson = { -> def jsonDir = tasks.downloadLicenses.jsonDestination def jsonFile = file("$jsonDir/license-dependency.json") new groovy.json.JsonSlurper().parseText(jsonFile.text) } tasks.downloadLicenses.ext.dependencyToLicenseJson = { -> def jsonDir = tasks.downloadLicenses.jsonDestination def jsonFile = file("$jsonDir/dependency-license.json") new groovy.json.JsonSlurper().parseText(jsonFile.text) } // Dependency license validation tasks.register("validateLicenses") { group = 'license' description = 'Checks 3rd-party dependency licenses against an allowlist' dependsOn tasks.downloadLicenses def excludeNeo4jPattern = /^(org|com)\.neo4j.*/ doLast { def allowListedNames = allowList.collect { it.name } tasks.downloadLicenses.dependencyToLicenseJson().dependencies .findAll { dep -> !dep.name.matches(excludeNeo4jPattern) } .findAll { dep -> allowListedNames.intersect(dep.licenses.collect { it.name }).isEmpty() } .each { dep -> logger.error("In project ${project.name}: Could not find an allowed license for dependency '$dep.name'. Details: ${dep.toMapString()}") } .each { dep -> throw new GradleException("The dependency '$dep.name' has no allowed license") } } } tasks.check.dependsOn tasks.validateLicenses tasks.register("generateLicensesFiles") { group = 'license' description 'Generates a LICENSES and NOTICE file with 3rd-party dependency license information' dependsOn tasks.downloadLicenses, tasks.validateLicenses def licenseFile = "$tasks.downloadLicenses.jsonDestination/LICENSES.txt" def noticesFile = "$tasks.downloadLicenses.jsonDestination/NOTICE.txt" ext.licensesFile = file(licenseFile) ext.noticeFile = file(noticesFile) outputs.file(ext.licensesFile) outputs.file(ext.noticeFile) doLast { // LICENSES.txt licensesFile.createNewFile() licensesFile.text = rootProject.file("$publicDir/licenses/headers/LICENSES-header.txt").text tasks.downloadLicenses.licenseToDependencyJson().licences .findAll { lic -> allowList.any { lic.name == it.name }} .sort { it.name }.each { licensesFile << '\n\n' licensesFile << "------------------------------------------------------------------------------\n" licensesFile << "$it.name\n" it.dependencies.sort { it }.each { licensesFile << " $it\n" } licensesFile << "------------------------------------------------------------------------------\n" licensesFile << '\n' licensesFile << rootProject.file("$publicDir/licenses/text/$it.name").text } // NOTICE.txt noticeFile.createNewFile() noticeFile.text = rootProject.file("$publicDir/licenses/headers/NOTICE-header.txt").text noticeFile << '\n\n' noticeFile << "Third-party licenses\n" noticeFile << "--------------------\n" tasks.downloadLicenses.licenseToDependencyJson().licences.sort { it.name }.each { noticeFile << '\n' noticeFile << "$it.name\n" it.dependencies.sort { it }.each { noticeFile << " $it\n" } } // Compare this file to what we have stored already, fail if they differ so that the PR fails and we are forced // to update it instead! File storedLicenseFile = new File("$project.rootDir/LICENSES.txt") boolean throwError = false if (licensesFile.readLines().size() != storedLicenseFile.readLines().size()) { throwError = true } for (def i = 0; i < licensesFile.readLines().size(); i++) { if (throwError) break if (licensesFile.readLines().get(i) != storedLicenseFile.readLines().get(i)) { throwError = true } } // Copy files to root project so they can be tracked copy { from licenseFile into "$project.rootDir" } copy { from noticesFile into "$project.rootDir" } // Throw after copy task gets run and the file is updated ready for commit :) // Note: You might need to do a `./gradlew clean` first if your file isn't updating! if (throwError) { throw new GradleException("The LICENSES.txt file has updated depenencies, please update by running `./gradlew generateLicensesFiles` and committing the changes.") } } } tasks.check.dependsOn tasks.generateLicensesFiles

简介

暂无描述 展开 收起
Java 等 5 种语言
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化