Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ it in the <NEO_HOME>/plugins directory of your Neo4j instance.

### Verifying the installation


You can check that the installation went well by:
Running `call dbms.procedures()`. The list of procedures should include a number of them prefixed by **n10s**.
Running `SHOW PROCEDURES WHERE name STARTS WITH "n10s"`.
The list of procedures should include a number of them prefixed by **n10s**.

If you installed the http endpoint, you can check it was correctly installed by looking in
the logs and making sure they show the following line on startup:
Expand Down Expand Up @@ -102,7 +104,7 @@ call n10s.graphconfig.init( { handleMultival: "ARRAY",

#### 2. Importing RDF data

Once the Graph config is created we can import data from a url using `fetch`:
Once the Graph config is created we can import data from an url using `fetch`:

```
call n10s.rdf.import.fetch( "https://raw.githubusercontent.com/jbarrasa/neosemantics/3.5/docs/rdf/nsmntx.ttl",
Expand Down
6 changes: 3 additions & 3 deletions docs/antora.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: neosemantics
version: '5.20'
version: '2025.06'
title: Neosemantics
nav:
- modules/ROOT/nav.adoc

asciidoc:
attributes:
docs-version: 5.20
page-neo4jversion: 5.20
docs-version: 2025.06
page-neo4jversion: 2025.06
page-product: Neosemantics
page-type: Neosemantics Manual
page-canonical-root: /labs/
3 changes: 2 additions & 1 deletion docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
// ** xref:reference.adoc#_utility_functions[12.2. Utility Functions]
// ** xref:reference.adoc#_extensions_http_endpoints[12.3. Extensions (HTTP endpoints)]
* xref:examples.adoc[13. Projects using Neosemantics]
* xref:appendix_migration.adoc[A. Migrating from neosemantics 3 to 4]
** xref:appendix_migration2025.adoc[A. Migrating from neosemantics 4.x and 5.x to 2025.x]
* xref:appendix_migration.adoc[B. Migrating from neosemantics 3 to 4]
// ** xref:appendix_migration.adoc#_who_should_read_this_guide[A.1. Who should read this guide]
// ** xref:appendix_migration.adoc#_changes_in_neosemantics_4_x[A.2. Changes in neosemantics 4.x]
3 changes: 2 additions & 1 deletion docs/modules/ROOT/pages/appendix_migration.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= Appendix A. Migrating from neosemantics 3 to 4
= Appendix B. Migrating from neosemantics 3 to 4
:page-pagination:

[appendix]
Expand All @@ -11,6 +11,7 @@ If you have previously used neosemantics v3.x, you can find the information you

This documentation is intended for users who are familiar with neosemantics. Based on this assumption, we are intentionally brief in the examples and comparisons.


=== Changes in neosemantics 4.x

Changes are grouped in two categories:
Expand Down
41 changes: 41 additions & 0 deletions docs/modules/ROOT/pages/appendix_migration2025.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
= Appendix A. Migrating to 2025.x


:page-pagination:

[abstract]
If you have previously used neosemantics up to v5.x, you can find the information you will need to migrate to using neosemantics v2025.x.

== Who should read this guide

This documentation is intended for users who are familiar with neosemantics. Based on this assumption, we are intentionally brief in the examples and comparisons.

=== Changes in neosemantics 2025.x

==== Changes to the URL structure of the RDF endpoint

Starting with Neo4j 2025.x that use recent versions of the Jetty web server (that is Jetty 12), the structure for URLs sent to the RDF description endpoint has become stricter. Passing a full URI containing encoded slashes (`%2F`) directly within the URL path is no longer permitted and will result in an `HTTP 400 Bad Request` error.

Therefore, the `/rdf/<dbname>/describe/<nodeid or uri>` endpoint is changed.

This change is a direct consequence of enhanced security policies in Jetty. Specifically, the `UriCompliance` mode, which is stricter by default, now flags ambiguous path separators to prevent potential 'Path Traversal' vulnerabilities. For more technical details, see the Jetty issue https://github.com/jetty/jetty.project/issues/12162[#12162] and the `AMBIGUOUS_PATH_SEPARATOR` definition in the https://github.com/jetty/jetty.project/blob/jetty-12.0.x/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/UriCompliance.java#L75[UriCompliance source code].

The correct way to describe a resource identified by a URI is to pass it as a query parameter named `nodeidentifier`.
Note that the URI should be encoded as before.

[options="header"]
|===
| Previous Method (No longer supported) | Correct Method (Required)
| The full URI was part of the *path*. | The full URI is passed as the `nodeidentifier` *query parameter*.
| `/rdf/<dbName>/describe/http%3A%2F%2Fneo4j.org%2Find%23neo4j355` | `/rdf/<dbName>/describe?nodeidentifier=http%3A%2F%2Fneo4j.org%2Find%23neo4j355`
|===

.Request Transformation Example
[source,http]
----
// OLD REQUEST (NOW RETURNS 400 ERROR)
GET /rdf/neo4j/describe/http%3A%2F%2Fneo4j.org%2Find%23neo4j355

// NEW REQUEST (CORRECT)
GET /rdf/neo4j/describe?nodeidentifier=http%3A%2F%2Fneo4j.org%2Find%23neo4j355
----
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/export.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ URIs need to be encoded in `GET` requests.

[source,Cypher]
----
:GET /rdf/neo4j/describe/http%3A%2F%2Fneo4j.org%2Find%23neo4j355?format=RDF/XML
:GET /rdf/neo4j/describe?nodeidentifier=http%3A%2F%2Fneo4j.org%2Find%23neo4j355?format=RDF/XML
----

Notice the URL encoding of the URI (the clean URI is `http://neo4j.org/ind#neo4j355`) and the `format` parameter to specify the serialisation format. Here's the output of the request:
Expand Down
3 changes: 2 additions & 1 deletion docs/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The guide covers the following areas:
* xref:inference.adoc[Chapter 11, Inferencing/Reasoning] — A detailed guide to inferencing and reasoning.
* xref:reference.adoc[Chapter 12, Neosemantics Reference] — An overview of all procedures and functions in the library.
* xref:examples.adoc[Chapter 13, Projects using Neosemantics] — A list of projects using n10s.
* xref:appendix_migration.adoc[Appendix A, Migrating from neosemantics 3 to 4] — A guide for neosemantics 3.x users
* xref:appendix_migration2025.adoc[Appendix A, Migrating from neosemantics 4.x and 5.x to 2025.x] — A guide for neosemantics 4.x and 5.x users
* xref:appendix_migration.adoc[Appendix B, Migrating from neosemantics 3 to 4] — A guide for neosemantics 3.x users

image::nsmntx-block-diagram.png[Neosemantics diagram, 200,align="center"]
6 changes: 3 additions & 3 deletions docs/modules/ROOT/pages/install.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

You can either download a prebuilt jar from the https://github.com/jbarrasa/neosemantics/releases[releases area] or build it from the source. If you prefer to build, check the note below.

1. Copy the the jar(s) in the <NEO_HOME>/plugins directory of your Neo4j instance. (**note:** If you're going to use the JSON-LD serialisation format for RDF, you'll need to include also link:/labs/apoc/[APOC])
1. Copy the jar(s) in the <NEO_HOME>/plugins directory of your Neo4j instance. (**note:** If you're going to use the JSON-LD serialisation format for RDF, you'll need to include also link:/labs/apoc/[APOC])
2. Add the following line to your <NEO_HOME>/conf/neo4j.conf (notice that it is possible to modify where the extension is mounted by using an alternative name to `/rdf` below).
+
[source,shell]
Expand All @@ -19,15 +19,15 @@ When the property `dbms.security.procedures.allowlist` is set, then it must incl
3. Restart the server.
4. Check that the installation went well by running
[source,cypher]
call dbms.procedures()
SHOW PROCEDURES WHERE name STARTS WITH "n10s"

The list of procedures should include the ones documented below.
You can check that the extension is mounted by running
[source,cypher]
----
:GET http://localhost:7474/rdf/ping
----
The previous command assumes you're running neo4j on your local machine, replace `localhos` with the host name if that is not the case.
The previous command assumes you're running neo4j on your local machine, replace `localhost` with the host name if that is not the case.

**Note on build**

Expand Down
3 changes: 1 addition & 2 deletions docs/modules/ROOT/pages/mapping.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ Let's use the `/cypher` method to serialise as RDF an order given its `orderID`.

[source,Cypher]
----
:POST /rdf/cypher
{ "cypher" : "MATCH path = (n:Order { orderID : '10785'})-[:ORDERS]->()-[:PART_OF]->(:Category { categoryName : 'Beverages'}) RETURN path " , "format": "RDF/XML" , "mappedElemsOnly" : true }

----

The Cypher query uses the elements in the Neo4j graph but the generated RDF uses schema.org vocabulary elements. The mapping we just defined is bridging the two. Note that the mapping is completely dynamic which means that any change to the mapping definition will be applied to any subsequent request.
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ a|
[cols="15,5,45,35"]
|===
| method| type| params| Description
| /rdf/<dbname>/describe/<nodeid or uri>
| /rdf/<dbname>/describe
|GET
a|
* the id of a node or the (urlencoded) uri
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/n10s/CommonProcedures.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.GZIPInputStream;
Expand All @@ -19,6 +20,7 @@
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.io.IOUtils;
import org.eclipse.rdf4j.common.lang.FileFormat;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFParser;
import org.eclipse.rdf4j.rio.Rio;
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/n10s/endpoint/RDFEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,21 @@ public Response ping() throws IOException {
}};
return Response.ok().entity(objectMapper.writeValueAsString(results)).build();
}

@GET
@Path("/{dbname}/describe/{nodeidentifier}")
@Path("/{dbname}/describe")
@Produces({"application/rdf+xml", "text/plain", "text/turtle", "text/n3",
"application/trig", "application/ld+json", "application/n-quads", "text/x-turtlestar",
"application/x-trigstar"})
public Response nodebyIdOrUri(@Context DatabaseManagementService gds,
@PathParam("dbname") String dbNameParam,
@PathParam("nodeidentifier") String nodeIdentifier,
@QueryParam("nodeIdentifier") String nodeIdentifier,
@QueryParam("graphuri") String namedGraphId,
@QueryParam("excludeContext") String excludeContextParam,
@QueryParam("mappedElemsOnly") String onlyMappedInfo,
@QueryParam("format") String format,
@HeaderParam("accept") String acceptHeaderParam) {
return Response.ok().entity((StreamingOutput) outputStream -> {

RDFWriter writer = startRdfWriter(getFormat(acceptHeaderParam, format), outputStream);
GraphDatabaseService neo4j = gds.database(dbNameParam);
try (Transaction tx = neo4j.beginTx()) {
Expand Down
6 changes: 2 additions & 4 deletions src/test/java/n10s/RDFProceduresTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package n10s;

import static n10s.CommonProcedures.UNIQUENESS_CONSTRAINT_ON_URI;
import static n10s.CommonProcedures.UNIQUENESS_CONSTRAINT_STATEMENT;
import static n10s.graphconfig.Params.PREFIX_SEPARATOR;
import static org.junit.Assert.assertArrayEquals;
Expand Down Expand Up @@ -2833,10 +2834,9 @@ public void multivalMultitypeSamePartialTx() throws Exception {

assertEquals(6, session.run("MATCH (n:Resource) RETURN count(n) as nodeCount ").next().get("nodeCount").asInt());

Result result = session.run("MATCH (n:Resource) RETURN n.ns0__totalLength as tl ");
Result result = session.run("MATCH (n:Resource) WHERE n.uri = \"http://dbpedia.org/resource/%22No_Flashlight%22:_Songs_of_the_Fulfilled_Night\" RETURN n.ns0__totalLength as tl");
Record next = result.next();
assertTrue(next.get("tl").asList().containsAll(Arrays.asList("45.75^^xsd__double", "2271.0"))); //"2271.0^^ns1__second" if custom datatypes were being kept

assertEquals(1L, session.run("MATCH (n:Resource) WHERE '45.75^^xsd__double' in n.ns0__totalLength RETURN count(n) as ct ").next().get("ct").asLong());

assertTrue(session.run("MATCH (r:Resource) DETACH DELETE r RETURN count(r) as ct").next().get("ct").asLong() > 0);
Expand Down Expand Up @@ -2866,9 +2866,7 @@ public void multivalMultitypeSamePartialTx() throws Exception {
assertEquals(6, session.run("MATCH (n:Resource) RETURN count(n) as nodeCount ").next().get("nodeCount").asInt());

assertEquals(1L, session.run("MATCH (n:Resource) WHERE '45.75^^xsd__double' in n.ns0__totalLength RETURN count(n) as ct ").next().get("ct").asLong());

}

}

@Test
Expand Down
Loading