DATAGRAPH-449 Updated docs for 3.0 (mostly for index related functionality)
This commit is contained in:
committed by
Michael Hunger
parent
f4bb615b34
commit
532aeb3189
@@ -79,7 +79,7 @@ h2. Maven configuration
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.4</version>
|
||||
<configuration>
|
||||
<outxml>true</outxml>
|
||||
<aspectLibraries>
|
||||
@@ -107,12 +107,12 @@ h2. Maven configuration
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.11.RELEASE</version>
|
||||
<version>1.7.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>1.6.11.RELEASE</version>
|
||||
<version>1.7.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
7
pom.xml
7
pom.xml
@@ -53,10 +53,17 @@
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>distribute</id>
|
||||
<properties>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>examples</id>
|
||||
<modules>
|
||||
<module>spring-data-neo4j-examples/hello-worlds</module>
|
||||
<module>spring-data-neo4j-examples/hello-worlds-aspects</module>
|
||||
<module>spring-data-neo4j-examples/imdb</module>
|
||||
<module>spring-data-neo4j-examples/cineasts</module>
|
||||
<module>spring-data-neo4j-examples/cineasts-aspects</module>
|
||||
|
||||
@@ -164,7 +164,7 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
|
||||
* @return the unique entity of type entityClass (if it exists) otherwise returns null.
|
||||
*
|
||||
*/
|
||||
public <T> T findUniqueEntity(final Class<T> entityClass,String propertyName, Object value) {
|
||||
/*public <T> T findUniqueEntity(final Class<T> entityClass,String propertyName, Object value) {
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = getPersistentEntity(entityClass);
|
||||
Neo4jPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(propertyName);
|
||||
|
||||
@@ -175,6 +175,7 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
|
||||
}
|
||||
return (T)getSchemaIndexProvider().findAll(persistentProperty,value).singleOrNull();
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return true if a transaction manager is available and a transaction is currently running
|
||||
|
||||
@@ -20,9 +20,12 @@ import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.neo4j.repository.GraphRepository;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.unique.common.CommonClub;
|
||||
import org.springframework.data.neo4j.unique.common.CommonUniqueClub;
|
||||
import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase;
|
||||
@@ -37,13 +40,20 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:unique-legacy-test-context.xml"})
|
||||
@Transactional
|
||||
public class UniqueLegacyIndexBasedEntityTests extends CommonUniqueEntityTestBase {
|
||||
|
||||
@Autowired
|
||||
private Neo4jTemplate neo4jTemplate;
|
||||
|
||||
@Autowired
|
||||
private ClubRepository clubRepository;
|
||||
|
||||
@@ -77,6 +87,45 @@ public class UniqueLegacyIndexBasedEntityTests extends CommonUniqueEntityTestBas
|
||||
assertEquals("Expected same node Ids", club1.getId(),club2.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingDistinctUniqueEntitiesViaNeo4jTemplateShouldResolveToDifferentEntities() {
|
||||
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
|
||||
|
||||
Map<String, Object> fooParams = new HashMap<String,Object>();
|
||||
fooParams.put("name","foo");
|
||||
fooParams.put("description","foo description");
|
||||
Map<String, Object> barParams = new HashMap<String,Object>();
|
||||
barParams.put("name","bar");
|
||||
barParams.put("description","foo description");
|
||||
|
||||
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
|
||||
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","bar", barParams, labels);
|
||||
|
||||
assertNotEquals("Expected different node Ids", club1.getId(), club2.getId());
|
||||
assertEquals(2, getUniqueClubRepository().count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingTheSameUniqueEntitiesViaNeo4jTemplateShouldResolveToOriginalEntity() {
|
||||
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
|
||||
|
||||
Map<String, Object> fooParams = new HashMap<String,Object>();
|
||||
fooParams.put("name","foo");
|
||||
fooParams.put("description","foo description");
|
||||
Map<String, Object> foo2Params = new HashMap<String,Object>();
|
||||
foo2Params.put("name","foo");
|
||||
foo2Params.put("description","bar description"); // Note: description differs but will be discarded
|
||||
|
||||
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
|
||||
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","foo", foo2Params, labels);
|
||||
|
||||
assertEquals("Expected the same node Ids", club1.getId(), club2.getId());
|
||||
assertEquals(1, getUniqueClubRepository().count());
|
||||
assertEquals("foo description", club2.getProperty("description"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonClub createNonUniqueClub(String name) {
|
||||
Club club = new Club();
|
||||
|
||||
@@ -20,8 +20,10 @@ import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.neo4j.repository.GraphRepository;
|
||||
import org.springframework.data.neo4j.support.Neo4jTemplate;
|
||||
import org.springframework.data.neo4j.unique.common.CommonClub;
|
||||
import org.springframework.data.neo4j.unique.common.CommonUniqueClub;
|
||||
import org.springframework.data.neo4j.unique.common.CommonUniqueEntityTestBase;
|
||||
@@ -36,15 +38,19 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:unique-schema-test-context.xml"})
|
||||
@Transactional
|
||||
public class UniqueSchemaBasedEntityTests extends CommonUniqueEntityTestBase {
|
||||
|
||||
@Autowired
|
||||
private Neo4jTemplate neo4jTemplate;
|
||||
|
||||
@Autowired
|
||||
private ClubRepository clubRepository;
|
||||
|
||||
@@ -81,6 +87,44 @@ public class UniqueSchemaBasedEntityTests extends CommonUniqueEntityTestBase {
|
||||
return (CommonUniqueClub)getUniqueClubRepository().findBySchemaPropertyValue(propertyName, value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingDistinctUniqueEntitiesViaNeo4jTemplateShouldResolveToDifferentEntities() {
|
||||
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
|
||||
|
||||
Map<String, Object> fooParams = new HashMap<String,Object>();
|
||||
fooParams.put("name","foo");
|
||||
fooParams.put("description","foo description");
|
||||
Map<String, Object> barParams = new HashMap<String,Object>();
|
||||
barParams.put("name","bar");
|
||||
barParams.put("description","foo description");
|
||||
|
||||
Node club1 = neo4jTemplate.merge(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
|
||||
Node club2 = neo4jTemplate.merge(UniqueClub.class.getSimpleName(),"name","bar", barParams, labels);
|
||||
|
||||
assertNotEquals("Expected different node Ids", club1.getId(), club2.getId());
|
||||
assertEquals(2, getUniqueClubRepository().count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingTheSameUniqueEntitiesViaNeo4jTemplateShouldResolveToOriginalEntity() {
|
||||
Collection labels = Arrays.asList( UniqueClub.class.getSimpleName(),"_"+ UniqueClub.class.getSimpleName() );
|
||||
|
||||
Map<String, Object> fooParams = new HashMap<String,Object>();
|
||||
fooParams.put("name","foo");
|
||||
fooParams.put("description","foo description");
|
||||
Map<String, Object> foo2Params = new HashMap<String,Object>();
|
||||
foo2Params.put("name","foo");
|
||||
foo2Params.put("description","bar description"); // Note: description differs but will be discarded
|
||||
|
||||
Node club1 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(), "name", "foo", fooParams, labels);
|
||||
Node club2 = neo4jTemplate.getOrCreateNode(UniqueClub.class.getSimpleName(),"name","foo", foo2Params, labels);
|
||||
|
||||
assertEquals("Expected the same node Ids", club1.getId(), club2.getId());
|
||||
assertEquals(1, getUniqueClubRepository().count());
|
||||
assertEquals("foo description", club2.getProperty("description"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CommonClub createNonUniqueClub(String name) {
|
||||
Club club = new Club();
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
distributed in print or electronically.
|
||||
</para>
|
||||
<para>
|
||||
Copyright 2010-2011 Neo Technology
|
||||
Copyright 2010-2014 Neo Technology
|
||||
</para>
|
||||
</legalnotice>
|
||||
|
||||
|
||||
@@ -74,16 +74,15 @@
|
||||
<title>Creating nodes and relationships</title>
|
||||
<para>
|
||||
Using the API of GraphDatabaseService, it is easy to create nodes and relate them to each other.
|
||||
Relationships are typed. Both nodes and relationships can have properties. Property values can be
|
||||
primitive Java types and Strings, or arrays of both. Node creation and
|
||||
modification has to happen within a transaction, while reading from the graph store can be
|
||||
done with or without a transaction.
|
||||
Relationships are typed and both nodes and relationships can have properties. Property values can be
|
||||
primitive Java types and Strings, or arrays of both. As of Neo4j 2.0, any operation on a
|
||||
node or relationship (creation, modification or simply reading) must happen within a transaction.
|
||||
</para>
|
||||
<example>
|
||||
<title>Neo4j usage</title>
|
||||
<programlisting language="java" ><![CDATA[GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "helloworld" );
|
||||
Transaction tx = graphDb.beginTx();
|
||||
try {
|
||||
<programlisting language="java" ><![CDATA[GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase("helloworld");
|
||||
|
||||
try (Transaction tx = graphDb.beginTx()) {
|
||||
Node firstNode = graphDb.createNode();
|
||||
firstNode.setProperty( "message", "Hello, " );
|
||||
Node secondNode = graphDb.createNode();
|
||||
@@ -93,8 +92,6 @@ try {
|
||||
DynamicRelationshipType.of("KNOWS") );
|
||||
relationship.setProperty( "message", "brave Neo4j" );
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.close();
|
||||
}
|
||||
]]></programlisting>
|
||||
</example>
|
||||
@@ -124,31 +121,40 @@ for (Path position : traversalDescription.traverse(myStartNode)) {
|
||||
<title>Indexing</title>
|
||||
<para>
|
||||
The best way for retrieving start nodes for traversals and queries is by using Neo4j's integrated index
|
||||
facilities. The <code>GraphDatabaseService</code> provides access to the <code>IndexManager</code> which in turn provides
|
||||
facilities.
|
||||
<note>
|
||||
<para>
|
||||
As of SDN 3.0 , schema based indexes (i.e. indexes based on labels) are the default, however
|
||||
the legacy indexing functionality still remains, as there is some functionality (for example full text
|
||||
searches, range searches) which is not possible/ available yet. It should be noted
|
||||
that legacy based indexes are deprecated in 3.0 and the intention is to eventually
|
||||
remove it completely as and when schema based indexes/functionality is fully able to support
|
||||
existing functionality.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
The <code>GraphDatabaseService</code> still provides access to the legacy <code>IndexManager</code> which in turn provides
|
||||
named indexes for nodes and relationships. Both can be indexed with property names and values.
|
||||
Retrieval is done with query methods on indexes, returning an <code>IndexHits</code> iterator.
|
||||
</para>
|
||||
<para>
|
||||
Spring Data Neo4j provides automatic indexing via the <code>@Indexed</code> annotation, eliminating the need
|
||||
for manual index management.
|
||||
Spring Data Neo4j provides automatic indexing via the <code>@Indexed</code> annotation, defaulting to make use
|
||||
of schema based indexes (aka labels), eliminating the need for manual index management.
|
||||
</para>
|
||||
<note><para>
|
||||
Modifying Neo4j indexes also requires transactions.
|
||||
</para></note>
|
||||
<example>
|
||||
<title>Index usage</title>
|
||||
<title>Legacy Index usage</title>
|
||||
<programlisting language="java"><![CDATA[IndexManager indexManager = graphDb.index();
|
||||
Index<Node> nodeIndex = indexManager.forNodes("a-node-index");
|
||||
Node node = ...;
|
||||
Transaction tx = graphDb.beginTx();
|
||||
try {
|
||||
try (Transaction tx = graphDb.beginTx()) {
|
||||
nodeIndex.add(node, "property","value");
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.close();
|
||||
}
|
||||
for (Node foundNode : nodeIndex.get("property","value")) {
|
||||
// found node
|
||||
try (Transaction tx = graphDb.beginTx()) {
|
||||
for (Node foundNode : nodeIndex.get("property","value")) {
|
||||
// found node
|
||||
}
|
||||
tx.success();
|
||||
}
|
||||
]]></programlisting>
|
||||
</example>
|
||||
@@ -164,9 +170,12 @@ for (Node foundNode : nodeIndex.get("property","value")) {
|
||||
<ulink url="http://video.neo4j.org/ybMbf/screencast-introduction-to-cypher/">Neo4j video site</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Cypher queries always begin with a <code>start</code> set of nodes. Those can be either expressed by their
|
||||
IDs or by an index lookup expression. Those start-nodes are then related to other nodes in the
|
||||
<code>match</code> clause. Start and match clauses can introduce new identifiers for nodes and
|
||||
As of Neo4 2.0, Cypher queries typically begin with a <code>match</code> clause, although the optional
|
||||
<code>start</code> clause (only really needed when using legacy indexes) is also still supported.
|
||||
The <code>match</code> clause can be used to provide a way to pattern match against a starting set of nodes, via their
|
||||
IDs or label based index lookup, with the legacy <code>start</code> clause providing similar functionality.
|
||||
These starting patterns or start nodes, are then related to other nodes via additional
|
||||
<code>match</code> clauses. Start and/or match clauses can introduce new identifiers for nodes and
|
||||
relationships. In the <code>where</code> clause additional filtering of the result set is applied by evaluating
|
||||
expressions. The <code>return</code> clause defines which part of the query result will be available.
|
||||
Aggregation also happens in the return clause by using aggregation functions on some of the values.
|
||||
@@ -182,7 +191,17 @@ for (Node foundNode : nodeIndex.get("property","value")) {
|
||||
<example>
|
||||
<title>Cypher Examples on the Cineasts.net Dataset</title>
|
||||
<programlisting><![CDATA[
|
||||
// Actors who played a Matrix movie:
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// schema based (Label) examples
|
||||
// ----------------------------------------------------------
|
||||
// TODO - once code has been updated
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// Legacy index based examples
|
||||
// ----------------------------------------------------------
|
||||
|
||||
// Actors who played a Matrix movie :
|
||||
start movie=node:Movie("title:Matrix*") match movie<-[:ACTS_IN]-actor
|
||||
return actor.name, actor.birthplace?
|
||||
|
||||
|
||||
@@ -11,18 +11,19 @@
|
||||
</para>
|
||||
<para>
|
||||
<note>
|
||||
Please not that the lucene based manual indexes are deprecated with Neo4j 2.0 and Spring Data Neo4j 3.0.
|
||||
The default index is now based on labels and schema indexes. Only for fulltext and spatial indexes the
|
||||
"legacy" index framework should be used. The related APIs have been deprecated as well.
|
||||
Please note that the lucene based manual indexes are deprecated with Neo4j 2.0 and Spring Data Neo4j 3.0.
|
||||
The default index is now based on labels and schema indexes and the related APIs have been deprecated as well.
|
||||
The "legacy" index framework should only be used for fulltext and spatial indexes which are not currently
|
||||
supported via schema based indexes.
|
||||
</note>
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Label based schema indexes</title>
|
||||
<title>Schema (Label based) indexes</title>
|
||||
<para>
|
||||
Since Neo4j version 2.0 indexes and unique constraints based on labels and properties are supported throughout the
|
||||
API including cypher. For properties of entities annotated with <code>@Indexed</code> an appropriate schema index
|
||||
and for <code>@Indexed(unique=true)</code> a constraint is created.
|
||||
API including cypher. For properties of entities annotated with <code>@Indexed</code>, this defaults to using the schema
|
||||
based strategy, and an appropriate schema index is created. For <code>@Indexed(unique=true)</code> a constraint is created.
|
||||
</para>
|
||||
<para>
|
||||
Those indexes will be automatically used by cypher queries that are generated for the derived finders and are
|
||||
@@ -30,28 +31,43 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<para>
|
||||
The Neo4j graph database employs different index providers for exact lookups and fulltext
|
||||
searches. Lucene is the default index provider implementation. Each named index is configured to be
|
||||
fulltext or exact. There is also a spatial index provider for geo-searches.
|
||||
</para>
|
||||
<section>
|
||||
<title>Legacy indexes</title>
|
||||
<para>
|
||||
If you would like to force a property on an entity to rather use the legacy index (instead of the
|
||||
default schema based index), then you will need to explicitly specify the type as either
|
||||
<code>@Indexed(indexType = IndexType.SIMPLE)</code> or <code>@Indexed(indexType = IndexType.FULLTEXT)</code>
|
||||
</para>
|
||||
<para>
|
||||
The Neo4j graph database employs different index providers for legacy exact (SIMPLE) lookups and fulltext
|
||||
searches. Lucene is the default index provider implementation. Each named index is configured to be
|
||||
fulltext or exact. There is also a spatial index provider for geo-searches.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Exact and numeric index</title>
|
||||
<para>
|
||||
When using the standard Neo4j API, nodes and relationships have to be manually indexed with
|
||||
key-value pairs, typically being the property name and value. When using Spring Data Neo4j,
|
||||
Prior to Neo4j 2.0, when using the standard Neo4j API, nodes and relationships had to be manually
|
||||
indexed with key-value pairs, typically being the property name and value. With the introduction
|
||||
of schemas and labels, indexing now happens automatically for you under the covers.
|
||||
When using Spring Data Neo4j,
|
||||
irrespective of whether you are using the newer schema based indexes or legacy indexes,
|
||||
this task is simplified to just adding an <code>@Indexed</code> annotation on entity fields
|
||||
by which the entity should be searchable. This will result in automatic updates of the index
|
||||
by which the entity should be searchable. This will result in automatic updates of the appropriate index
|
||||
every time an indexed field changes.
|
||||
</para>
|
||||
<para>
|
||||
Numerical fields are indexed numerically so that they are available for range queries. All
|
||||
Numerical fields are indexed numerically so that they are available for range queries.
|
||||
<note><para>Automatic numerical range queries are not currently supported for
|
||||
schema based numeric indexes.</para></note>
|
||||
All
|
||||
other fields are indexed with their string representation. If a numeric field should not be
|
||||
indexed numerically, it is possible to switch it off with <code>@Indexed(numeric=false)</code>.
|
||||
</para>
|
||||
<para>
|
||||
The <code>@Indexed</code> annotation also provides the option of using a custom index name. The default index
|
||||
The <code>@Indexed</code> annotation also provides the option of using a custom index name (for legacy
|
||||
indexes). The default index
|
||||
name is the simple class name of the entity, so that each class typically gets its own index.
|
||||
It is recommended to not have two entity classes with the same class name, regardless of
|
||||
package.
|
||||
@@ -63,28 +79,51 @@
|
||||
that is provided or of the actual entity instance.
|
||||
</para>
|
||||
<para>
|
||||
The indexes can be queried by using a repository (see
|
||||
The schema based indexes can be queried by using a repository (see
|
||||
<xref linkend="reference_programming-model_repositories" />).
|
||||
The repository is an instance of
|
||||
<code>org.springframework.data.neo4j.repository.SchemaIndexRepository</code>.
|
||||
The methods <code>findBySchemaPropertyValue()</code> and <code>findAllBySchemaPropertyValue()</code> work on
|
||||
the exact indexes and return the first or all matches. Range queries are not supported yet.
|
||||
</para>
|
||||
<para>
|
||||
The legacy indexes can also be queried by using a repository (see
|
||||
<xref linkend="reference_programming-model_repositories" />).
|
||||
The repository is still an instance of the deprecated
|
||||
<code>org.springframework.data.neo4j.repository.IndexRepository</code>.
|
||||
The methods <code>findByPropertyValue()</code> and <code>findAllByPropertyValue()</code> work on
|
||||
the exact indexes and return the first or all matches. To do range queries, use
|
||||
<code>findAllByRange()</code> (please note that currently both values are inclusive).
|
||||
</para>
|
||||
<para>
|
||||
For providing explicit index names the repository has to extend <code>NamedIndexRepository</code>.
|
||||
When providing explicit index names (for legacy indexes) the repository has to extend <code>NamedIndexRepository</code>.
|
||||
This adds the shown methods with another signature that take the index name as first parameter.
|
||||
</para>
|
||||
<example>
|
||||
<title>Indexing entities</title>
|
||||
<title>Exact (schema based) indexes</title>
|
||||
<programlisting language="java"><![CDATA[@NodeEntity
|
||||
class Person {
|
||||
@Indexed(indexName = "people") String name;
|
||||
@Indexed String name;
|
||||
@Indexed int age;
|
||||
}
|
||||
|
||||
GraphRepository<Person> graphRepository = template.repositoryFor(Person.class);
|
||||
|
||||
// Exact match, in named index
|
||||
Person mark = graphRepository.findBySchemaPropertyValue("name", "mark");
|
||||
]]></programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Exact (legacy) indexes</title>
|
||||
<programlisting language="java"><![CDATA[@NodeEntity
|
||||
class Person {
|
||||
@Indexed(indexName = "people",indexType = IndexType.SIMPLE) String name;
|
||||
@Indexed(indexType = IndexType.SIMPLE) int age;
|
||||
}
|
||||
|
||||
GraphRepository<Person> graphRepository = template.repositoryFor(Person.class);
|
||||
|
||||
// Exact match, in named index
|
||||
Person mark = graphRepository.findByPropertyValue("people", "name", "mark");
|
||||
|
||||
@@ -97,9 +136,10 @@ for (Person middleAgedDeveloper : graphRepository.findAllByRange("age", 20, 40))
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<title>Fulltext indexes</title>
|
||||
<title>Fulltext (legacy) indexes</title>
|
||||
<para>
|
||||
Spring Data Neo4j also supports fulltext indexes. By default, indexed fields are stored in
|
||||
Spring Data Neo4j also supports fulltext indexes - currently still only via the legacy
|
||||
indexes. By default, legacy indexed fields are stored in
|
||||
an exact lookup index. To have them analyzed and prepared for fulltext search, the
|
||||
<code>@Indexed</code> annotation has the <code>type</code> attribute which can be set to <code>IndexType.FULLTEXT</code>.
|
||||
|
||||
@@ -118,7 +158,7 @@ for (Person middleAgedDeveloper : graphRepository.findAllByRange("age", 20, 40))
|
||||
<title>Fulltext indexing</title>
|
||||
<programlisting language="java"><![CDATA[@NodeEntity
|
||||
class Person {
|
||||
@Indexed(indexName = "people-search", type=FULLTEXT) String name;
|
||||
@Indexed(indexName = "people-search", indexType=IndexType.FULLTEXT) String name;
|
||||
}
|
||||
|
||||
GraphRepository<Person> graphRepository =
|
||||
@@ -130,7 +170,7 @@ Person mark = graphRepository.findAllByQuery("people-search", "name", "ma*");
|
||||
|
||||
</para>
|
||||
<note><para>
|
||||
Please note that indexes are currently created on demand, so whenever an index that doesn't exist
|
||||
Please note that the legacy indexes are currently created on demand, so whenever an index that doesn't exist
|
||||
is requested from a query or get operation it is created. This is subject to change but has
|
||||
currently the implication that those indexes won't be configured as fulltext which causes
|
||||
subsequent fulltext updates to those indexes to fail.
|
||||
@@ -139,30 +179,34 @@ Person mark = graphRepository.findAllByQuery("people-search", "name", "ma*");
|
||||
<section>
|
||||
<title>Unique indexes</title>
|
||||
<para>
|
||||
Unique indexing with <code>index.putIfAbsent</code> and <code>UniqueFactory</code> was introduced in Neo4j 1.6.
|
||||
It is also available via the REST API.
|
||||
In Spring Data Neo4j this is made available via <code>Neo4jTemplate.getOrCreateNode</code> and
|
||||
<code>Neo4jTemplate.getOrCreateRelationship</code>.
|
||||
Unique indexing can be applied either via the inbuilt schema (label based) unique constraint for nodes, or,
|
||||
via the legacy <code>index.putIfAbsent</code> and <code>UniqueFactory</code> code for both nodes and relationships.
|
||||
In Spring Data Neo4j this is done by setting the <code>unique=true</code> property on the <code>@Indexed</code> annotation.
|
||||
Methods for programmatically getting and/or creating unique entities is available on the <code>Neo4jTemplate</code> class, namely
|
||||
<code>getOrCreateNode</code> and <code>getOrCreateRelationship</code> for legacy indexes, and <code>merge</code> for schema based
|
||||
unique entities.
|
||||
</para>
|
||||
<para>In an entity at most one field can be annotated with <code>@Indexed(unique=true)</code> regardless of the index-type used.
|
||||
The uniqueness will be taken into account when creating the entity by reusing an existing entity if that unique key-combination
|
||||
already exists. On saving of the field it will be cross-checked against the index and fail with a DataIntegrityViolationException
|
||||
if the field was changed to an already existing unique value. Null values are no longer allowed for these properties.
|
||||
already exists. On saving of the field it will be cross-checked against the schema or legacy index and fail with a
|
||||
DataIntegrityViolationException if the field was changed to an already existing unique value.
|
||||
Null values are no longer allowed for these properties.
|
||||
</para>
|
||||
<para>
|
||||
<note>
|
||||
This works for both Node-Entities as well as Relationship-Entities. Relationship-Uniqueness in Neo4j is global so that
|
||||
This works for both Node-Entities as well as Relationship-Entities (legacy indexes only). Relationship-Uniqueness in Neo4j is global so that
|
||||
an existing unique instance of this relationship may connect two completely different nodes and might also have a
|
||||
different type.
|
||||
</note>
|
||||
</para>
|
||||
<para>
|
||||
<example>
|
||||
<title>Unique indexing</title>
|
||||
<title>Unique indexing (Schema Based)</title>
|
||||
<programlisting language="java"><![CDATA[
|
||||
// creates or finds a node with the unique index-key-value combination
|
||||
// creates or finds a node with the unique label-key-value combination
|
||||
// and initializes it with the properties given
|
||||
template.getOrCreateNode("users", "login", "mh", map("name","Michael","age",37));
|
||||
List labels = getTRSLabels(Person.class);
|
||||
template.merge("Person", "name", "Michael", map("name","Michael","age",37),labels);
|
||||
|
||||
@NodeEntity class Person {
|
||||
@Indexed(unique = true) String name;
|
||||
@@ -179,6 +223,31 @@ Person thomas = repository.save(new Person("thomas"));
|
||||
thomas.setName("mark");
|
||||
repository.save(thomas); // fails with a DataIntegrityViolationException
|
||||
|
||||
]]></programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Unique indexing (Legacy Based)</title>
|
||||
<programlisting language="java"><![CDATA[
|
||||
// creates or finds a node with the unique index-key-value combination
|
||||
// and initializes it with the properties given
|
||||
List labels = getTRSLabels(Person.class);
|
||||
template.getOrCreateNode("Person", "name", "Michael", map("name","Michael","age",37),labels);
|
||||
|
||||
@NodeEntity class Person {
|
||||
@Indexed(indexType = IndexType.SIMPLE, unique = true) String name;
|
||||
}
|
||||
|
||||
Person mark1 = repository.save(new Person("mark"));
|
||||
Person mark2 = repository.save(new Person("mark"));
|
||||
|
||||
// just one node is created
|
||||
assertEquals(mark1,mark2);
|
||||
assertEquals(1, personRepository.count());
|
||||
|
||||
Person thomas = repository.save(new Person("thomas"));
|
||||
thomas.setName("mark");
|
||||
repository.save(thomas); // fails with a DataIntegrityViolationException
|
||||
|
||||
]]></programlisting>
|
||||
</example>
|
||||
|
||||
@@ -186,12 +255,12 @@ repository.save(thomas); // fails with a DataIntegrityViolationException
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Manual index access</title>
|
||||
<title>Manual (Legacy) index access</title>
|
||||
<para>
|
||||
The index for a domain class is also available from <code>Neo4jTemplate</code> via
|
||||
The legacy index for a domain class is also available from <code>Neo4jTemplate</code> via
|
||||
the <code>getIndex()</code> method. The second parameter is optional and takes the index name
|
||||
if it should not be inferred from the class name. It returns the index implementation that is
|
||||
provided by Neo4j.
|
||||
provided by Neo4j. Note: Manual Legacy index access is deprecated in SDN 3.0
|
||||
</para>
|
||||
<example>
|
||||
<title>Manual index retrieval by type and name</title>
|
||||
|
||||
@@ -98,13 +98,13 @@
|
||||
<title>Java-based configuration</title>
|
||||
<programlisting language="java"><![CDATA[
|
||||
@Configuration
|
||||
@EnableNeo4jRepositories(basePackages = "org.springframework.data.neo4j.ref.whatever.repositories")
|
||||
@EnableNeo4jRepositories(basePackages = "org.example.repositories")
|
||||
static class Config extends Neo4jConfiguration {
|
||||
|
||||
Config() {
|
||||
// Equivalent of setting basePackage for XML based <neo4j:config base-package=".."/>
|
||||
// (This will probably move into an/the @EnableNeo4jRepositories in the future)
|
||||
setBasePackage("org.springframework.data.neo4j.model,org.springframework.data.neo4j.repository.query");
|
||||
setBasePackage("org.example.domain");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user