View
408
Download
4
Category
Preview:
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.
Citation preview
$(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… ;-)
Recommended