[FR] Introduction à Spring Data Neo4j 3.x

Post on 28-Nov-2014

405 views 4 download

description

22nd of May - Graph DB Meetup @ Lyon, FR Contents in French this time Details all capabilities offered by Neo4j. More info : http://www.meetup.com/graphdb-Lyon/events/175401022/ Please not all attendants were techies, that's why I felt compelled to remind what Spring is and is not.

Transcript of [FR] Introduction à Spring Data Neo4j 3.x

$(Graph Meetup)> who am i

Florent Biville (@fbiville)

(Développeur [OSS]|formateur|associé) à

Co-créateur de Spring Meetup Paris (@interface21_ug)

Partenaire @Neo4j depuis 2012 (& formateur Neo4j !)

Spring Data Neo4j - au menu

1. Spring ?

2. Spring Data ?

3. Spring Data Neo4j ?

Spring ?

Spring

À ses débuts (2003)

Spring == Spring Framework == framework de DI

Dependency Injection - brefs rappels

Spring

public class InstantMessagingClient implements MessagingClient {

private final InstantMessagingService instantMessagingService;

private final UserSessionService userSessionService;

public InstantMessagingClient(InstantMessagingService instantMessagingService,

UserSessionService userSessionService) {

this.instantMessagingService = instantMessagingService;

this.userSessionService = userSessionService;

}

public void sendMessage(Message message) {

if (userSessionService.isCurrentlyLogged(message.getAuthorName())) {

instantMessagingService.sendMessage(message);

}

}

}

Spring

public class InstantMessagingClient implements MessagingClient {

private final InstantMessagingService instantMessagingService;

private final UserSessionService userSessionService;

public InstantMessagingClient(InstantMessagingService instantMessagingService,

UserSessionService userSessionService) {

this.instantMessagingService = instantMessagingService;

this.userSessionService = userSessionService;

}

public void sendMessage(Message message) {

if (userSessionService.isCurrentlyLogged(message.getAuthorName())) {

instantMessagingService.sendMessage(message);

}

}

}

Spring

Dependency Injection - idée

Ne pas assembler InstantMessagingClient soi-

même, déléguer plutôt à une brique logicielle tierce.

Spring

Dependency Injection - intérêts

Découpler son logiciel d’un “assemblage” particulier de

InstantMessagingClient (ex: assembler un service

de tests pour les tests automatisés)

Spring

Dependency Injection - avec Spring Framework

Spring

Notion de bean = description d’un “assemblage” = recette

de créations d’objets

Notion de context = groupe de beans

Plusieurs formats de description :

XML (historique), Java, annotations Java

Spring

Déclaration de context en XML Déclaration de context en Java

<beans[...]>

<import resource=”classpath:my-services.xml” />

<bean id=”instantMessagingClient” class=”com.

acme.InstantMessagingClient”>

<constructor-arg ref=”instantMsgService” />

<constructor-arg ref=”userSessionService” />

</bean>

</beans>

@Configuration

@Import(MyServiceContext.class)

public class MyProductionContext {

@Bean

public MessagingClient instantMessagingClient

(InstantMessagingService msgService,

UserSessionService userService)

return new InstantMessagingClient(

msgService, userService

);

}

Spring

Dependency Injection par annotation

Côté contexte : <component-scan /> (XML) ou @ComponentScan (Java) permet de scanner tout un ensemble de beans sans avoir à les déclarer explicitement.

@Component

public class InstantMessagingClient implements MessagingClient {

[...]

@Autowired // ou @Inject (standard Java EE)

public InstantMessagingClient(InstantMessagingService instantMessagingService,

UserSessionService userSessionService) {

[...]

}

[...]

}

Spring

À ses débuts (2003)

Spring == Spring Framework == framework de DI

Devient un standard de facto (vs. le standard officiel J2EE)

Spring

Depuis,

Spring = écosystème alternatif|complémentaire à Java EE

Spring

Spring

La plupart des briques logicielles de l’écosystème Spring

repose sur Spring Framework...

Spring

… dont Spring Data !

Spring

Spring Data ?

Contexte historique

Hégémonie des RDBMS jusqu’à il y a “peu” (NOSQL!).

Impacts côté Java,

hégémonie des ORM (Hibernate, EclipseLink...)

émergence d’un standard (JPA)

Spring Data

Philosophie

Concilier

la familiarité des API comme JPA,

la flexibilité de Spring Framework,

les spécificités d’un maximum de stores NOSQL.

Spring Data

Spring Data

Spring Data

Objection !

Spring Data

Les ORM peuvent s’appuyer

sur le standard SQL commun aux SGDBR.

Spring Data

Il n’existe aucun standard partagé par les stores NOSQL.

Spring Data

Comment Spring Data peut-il

prétendre à une API homogène

autour de stores NOSQL qui ne le

sont pas ?

Spring Data

Spring Data Commons - idée

Module parent de tous les modules Spring Data.

Regroupe les traits communs des stores supportés.

Définit les concepts partagés de base.

Spring Data

Entité ~ description orientée objet d’un enregistrement

Repository ~ encapsulation des opérations de

requêtage sur une collection d’objets (ici : entités)

Template ~ encapsulation des opérations bas niveau

spécifiques à un service particulier (JdbcTemplate…)

Spring Data

Spring Data Commons - entités

Spring Data

Notion de mapping

représentation objet (entité) <-> représentation du store

chaque module SD implémente son propre mapping

exemples : @NodeEntity (SD Neo4j), @Document (SD Mongo)...

Spring Data

Spring Data Commons - repositories

Spring Data

Encapsule les contrats d’opérations de requêtage

communes à la plupart des stores : écriture, lecture, mise à

jour…

Ces opérations sont réparties dans une hiérarchie d’

interfaces Java.

Spring Data

Spring Data

Repository<T, ID>

Interface “marker” permettant de

déclencher l’inclusion de ses

implémentations

automatiquement et la génération

de méthodes finder

dynamiques.

T = type de l’entité

ID = type de l’identifiant technique

Méthodes finder dynamiques

Idée : déduire (au runtime) l’implémentation des

méthodes de Repository par leur signature (merci Ruby on

Rails).

Spring Data

public interface PersonRepository extends Repository<Person, Long> {

List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);

List<Person> findByLastnameIgnoreCase(String lastname);

List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

List<Person> findByLastnameOrderByFirstnameAsc(String lastname);

List<Person> findByLastnameOrderByFirstnameDesc(String lastname);

}

Spring Data

@Service

public class JdbcPersonService implements PersonService {

private final PersonRepository repository;

@Autowired

public PersonService(PersonRepository repository) {

this.repository = repository;

}

@Transactional

public List<Person> findByLastnameIgnoreCase(String lastName) {

return repository.findByLastnameIgnoreCase(lastName);

}

// [...]

}

Spring Data

Méthodes finder dynamiques

Aucune écriture d’implémentation de PersonRepository !

Les développeurs se focalisent sur le code métier

(JdbcPersonService).

Spring Data

Spring Data

Repository<T, ID>

Interface “marker” permettant de

déclencher l’inclusion de ses

implémentations

automatiquement et la génération

de méthodes finder

dynamiques.

T = type de l’entité

ID = type de l’identifiant technique

Spring Data

Repository<T, ID> Définit les opérations

élémentaires sur les entités

(création, lecture, mise à jour,

suppression).

CrudRepository<T, ID>

T = type de l’entité

ID = type de l’identifiant technique

Spring Data

Repository<T, ID>

Introduit des critères de tri &

pagination sur les requêtes de

lecture globale.CrudRepository<T,

ID>

PagingAndSortingRepository<T, ID>T = type de l’entité

ID = type de l’identifiant technique

Spring Data

Repository<T, ID>

T = type de l’entité

ID = type de l’identifiant technique

CrudRepository<T, ID>

PagingAndSortingRepository<T, ID>

Chaque module Spring Data (et

chaque développeur!) est ensuite

libre non seulement d’

implémenter mais de spécialiser

ces contrats transverses.

Comment Spring Data peut-il

prétendre à une API homogène

autour de stores NOSQL qui ne le

sont pas ?

Spring Data

En introduisant

1 API commune minimaliste

Mais aussi des extensions d’

API par type de store !

Spring Data

Exemple d’utilisation : Redbasin (article)

Idée : concilier l’immensité des informations disponibles

autour de la recherche de traitements contre le cancer

pour détecter au plus vite les traitements inefficaces.

Utilisation de Spring Data pour

Neo4j/Mongo DB/Redis/Hadoop.

Spring Data

Spring Data Neo4j ?

Module fils (historique!) de Commons

dédié à l’interfaçage avec … Neo4j,

fournit des entités, repositories,

templates orientés graphe !

Spring Data Neo4j

Version actuelle : 3.1.0.RELEASE.

Depuis 3.0.0.RELEASE (24 février 2014),

Neo4j 2.0 est officiellement supporté.

Spring Data Neo4j

Spring Data Neo4j - mapping & entités

Spring Data Neo4j

Deux types d’entités : @NodeEntity, @RelationshipEntity

Deux modes de mapping : simple & avancé

Plusieurs stratégies de représentation des métadonnées de

mapping au sein du graphe.

Spring Data Neo4j

Entités@NodeEntity, @RelationshipEntity

Support basique de la JSR-303 (Bean Validation)

Projection de résultats de traversées possible (via

FieldTraversalDescriptionBuilder).

Cycle de vie à la JPA : detached, attached.

Spring Data Neo4j

@NodeEntity

public class Person {

@GraphId // Optionnel si utilisation du mapping avancé

private Long nodeId;

@Indexed(unique=true) // Index façon 2.0

private String id;

@Indexed(indexType = IndexType.FULLTEXT, indexName = "people") // Index legacy

@Size(min = 2, max = 50) // JSR-303

private String name;

@RelatedTo(type="OWNS", enforceTargetType=true) // @RelationshipEntity non requise

private Car car;

@RelatedToVia(type="FRIEND_OF", direction=Direction.INCOMING)

private Iterable<Friendship> friendships;

// [...] constructeurs, getters/setters, equals/hashCode

}

Spring Data Neo4j

@RelationshipEntity(type = "ACTS_IN")

public class Role {

@GraphId

private Long id;

@EndNode

private Movie movie;

@StartNode

private Actor actor;

private String name; // implicitement persisté (version explicite : @GraphProperty)

@GraphTraversal(traversal=PeopleTraversalBuilder.class, params="persons")

private Iterable<Relationship> peopleRelationships;

// [...] constructeurs, getters/setters, equals/hashCode

}

Spring Data Neo4j

Mapping avancé

Idée : intercepter les accès aux entités (classes

annotées @NodeEntity ou @RelationshipEntity) afin de les

enrichir d’informations supplémentaires.

Spring Data Neo4j

Mapping avancé

Aspects Neo4jRelationshipBacking et Neo4jNodeBacking.

Introduction d’un champ EntityState (~noeud /

relation sous-jacente) et de méthodes de

persistence (Active Record).

Spring Data Neo4j

Mapping simple

Chaque classe entité inclut explicitement un champ

annoté @GraphId (nécessairement de type Long) où sera

persisté l’ID technique des noeuds/relations.

Spring Data Neo4j

Mapping, côté graphe

Différentes stratégies de représentation possibles.

Spring Data Neo4j

Noeud <-> @NodeEntity Relation <-> @RelationshipEntity

LabelBasedNodeTypeRepresentationStrategy IndexBasedRelationshipTypeRepresentationStrategy

IndexBasedNodeTypeRepresentationStrategy

SubReferenceNodeTypeRepresentationStrategy NoopRelationshipTypeRepresentationStrategy

NoopNodeTypeRepresentationStrategy

Mapping, côté graphe

LabelBased (défaut pour noeuds): chaque noeud se voit

assigner un label correspondant au nom qualifié (ou

aliasé) de son entité Java.

Spring Data Neo4j

Mapping, côté graphe

IndexBased (défaut pour rels): un index __types__ est

créé où sont indexés les champs __type__ ajouté

automatiquement aux noeuds/relations

Spring Data Neo4j

Mapping, côté graphe

SubReference (legacy): l’arbre d’entités Java est

persisté comme un sous-graphe dans Neo4j. Les

noeuds du graphe s’y lient avec des relations de type

INSTANCE_OF. Il annule le mapping des relations (cf.

Noop).

Spring Data Neo4j

Mapping, côté graphe

Noop : ne fait rien (principalement utilisé pour les tests

internes à SDN) :)

Spring Data Neo4j

Le mapping entités-graphe est déclenché via l’utilisation

des repositories ou de Neo4jTemplate.

Spring Data Neo4j

Spring Data Neo4j - repositories

Spring Data Neo4j

Spring Data Neo4jRepository<T,

ID>

CrudRepository<T, ID>

PagingAndSortingRepository<T, ID>

GraphRepository<T>

Outre les opérations de base,

cette interface expose les

opérations d’indexations (pre- et

post-2.0) et de traversée via des

interfaces intermédiaires (non

illustrées ici) comme

findAllByTraversal…T = type de l’entité

ID = type de l’identifiant technique

Spring Data Neo4j// côté repository

public interface TweetRepository extends GraphRepository<Tweet> {

List<Tweet> findByPosterName(String poster);

}// côté service

@Service

@Transactional

public class TwitterService implements SocialService {

@Autowired // préférez par constructeur ou par setter

private TweetRepository tweetRepository;

@Transactional(readOnly = true)

public Tweets findTweetsAuthoredBy(String poster) {

return Tweets.of(tweetRepository.findByPosterName(poster));

}

}

Il est également possible de définir des requêtes Cypher

particulières (toujours pas d’implémentation à écrire !)

public interface UserRepository extends GraphRepository<User> {

@Query( "MATCH (me:User {user:{name}})-[:POSTED]->(tweet)-[:MENTIONS]->(user)" +

" WHERE me <> user " +

" RETURN distinct user")

Set<User> suggestFriends(@Param("name") String user);

}

Spring Data Neo4j

Il existe aussi d’autres repositories tels que

SpatialRepository (requêtes géospatiales),

CypherDslRepository<T> pour utiliser le DSL Cypher

Java et des intégrations avec QueryDSL (voire de les

combiner).

Spring Data Neo4j

Spring Data Neo4j - template

Spring Data Neo4j

Encapsule l’API Neo4j avec une gestion implicite des

transactions (et une optimisation des requêtes HTTP en

mode REST).

Permet la manipulation des entités et offre un système

basique d’écoute d’événements (Spring Framework) :

{Before|After}{Save|Delete}Event

Spring Data Neo4j

Spring Data Neo4j - cross-store persistence

Spring Data Neo4j

Permet de persister une partie des informations portée par

les entités dans Neo4j et l’autre dans un SGDBR (via JPA).

Spring Data Neo4j

L’entité ne sera persistée dans le graphe qu’une fois

persistée dans le SGDBR (ID JPA assigné). Un champ

FOREIGN_ID (FQN + ID JPA) est ensuite ajouté au noeud

du graphe.

Les aspects de SDN rendent les champs annotés

@GraphProperty transients pour JPA.

Spring Data Neo4j

@Entity // JPA

@NodeEntity(partial = true) // Spring Data Neo4j

public class User {

@Id

@GeneratedValue(strategy = GenerationType.TABLE, generator = "id_gen")

@TableGenerator(name = "id_gen", table = "SEQUENCE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SEQ_GEN", allocationSize = 1)

private Long id; // ID JPA

private String name;

@GraphProperty

@Indexed

String nickname;

@RelatedToVia(type = "recommends", elementClass = Recommendation.class)

Iterable<Recommendation> recommendations;

}

Spring Data Neo4j

Conclusion

?Ça continue sur Twitter (@fbiville, @LateraIThoughts, @Neo4jFr),

le Google Groups Neo4jFR,

les meetups… ;-)