I database dei grafici sono sempre più popolari nelle applicazioni moderne perché possono modellare le relazioni complesse in modo nativo. I grafici forniscono una rappresentazione più naturale dei dati connessi dai sistemi di raccomandazione al rilevamento delle frodi. I nostri articoli precedenti hanno esplorato ampiamente i database grafici e approfonditi in Neo4j. In questa terza parte, ci concentriamo Janusgraphun database grafico scalabile e distribuito.
A differenza di NEO4J, Janusgraph supporta più backend e leverali Apache Tinkerpopun framework di calcolo dei grafici che introduce un’API commonplace e un linguaggio di question (Gremlin) per vari database. Questa astrazione rende Janusgraph una scelta flessibile per le applicazioni aziendali.
Comprensione di Janusgraph e Tinkerpop
Janusgraph è un database di grafici distribuiti a sodo che gestisce enormi volumi di dati transazionali e analitici. Supporta diversi backend di archiviazione e indicizzazione, tra cui Cassandra, Hbase, Berkeleydb ed Elasticsearch.
Implementa il Framework di Tinkerpopche fornisce due componenti principali:
- Gremlin: Un linguaggio di attraversamento del grafico (sia dichiarativo che imperativo).
- API TINKERPOP: Un insieme di interfacce per lavorare con database grafici su motori diversi.
Ciò consente agli sviluppatori di scrivere codice agnostico del database su qualsiasi motore compatibile con TinkerPop conforme.
Gremlin è un linguaggio funzionale basato su gradini per interrogare le strutture grafiche. Si concentra su Traversals: l’atto di camminare attraverso un grafico. Gremlin supporta i casi di utilizzo OLTP (in tempo reale) e OLAP (Analytics) su oltre 30 fornitori di database grafici.
Caratteristica | SQL | Gremlin |
---|---|---|
Recupero di entità | Seleziona * dal libro | gv (). Haslabel (‘libro’) |
Filtraggio | Dove identify = “java” | ha (“nome”, “java”) |
Be part of/Relationship | Unisciti a Book_Category su … | Gv (). Haslabel (‘libro’). Out (‘is’). Haslabel (‘categoria’) |
Raggruppamento e conteggio | Gruppo per categoria_id | gruppo (). per (‘categoria’). per (depend ()) |
Flessibilità dello schema | Schema fisso | Proprietà dinamiche, schema-opzionale |
Janusgraph Supporta configurazioni sia incorporate che esterne. Per iniziare rapidamente usando Cassandra ed Elasticsearch, esegui questo docker-compose
file:
model: '3.8'
providers:
cassandra:
picture: cassandra:3.11
ports:
- "9042:9042"
elasticsearch:
picture: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
setting:
- discovery.sort=single-node
- xpack.safety.enabled=false
ports:
- "9200:9200"
janusgraph:
picture: janusgraph/janusgraph:newest
depends_on:
- cassandra
- elasticsearch
ports:
- "8182:8182"
setting:
- gremlin.graph=org.janusgraph.core.ConfiguredGraphFactory
- storage.backend=cql
- storage.hostname=cassandra
- index.search.backend=elasticsearch
- index.search.hostname=elasticsearch
In alternativa, è possibile evitare le dipendenze esterne interamente per lo sviluppo locale o gli ambienti incorporati. Janusgraph supporta Modalità incorporata usando Berkeleydb Java Version (Berkeleyje) per l’archiviazione del grafico locale e Lucene come motore di indicizzazione. Ciò è particolarmente utile per la prototipazione rapida o l’esecuzione di check unitari senza impostare l’infrastruttura.
Berkeleyje è un negozio di valore chiave veloce e incorporabile scritto in Java, che memorizza i tuoi dati grafici direttamente sul filesystem locale.
Ecco una configurazione di esempio per la modalità incorporata:
storage.backend=berkeleyje
storage.listing=../goal/jnosql/berkeleyje
index.search.backend=lucene
index.search.listing=../goal/jnosql/lucene
Nel caso in cui si desideri eseguire con Casandra, aggiorna le proprietà in questa modalità:
jnosql.graph.database=janusgraph
storage.backend=cql
storage.hostname=localhost
index.search.backend=elasticsearch
index.search.hostname=localhost
Prima di modellare il dominio, dobbiamo definire la struttura delle entità che rappresenteranno il nostro grafico. In questo caso, utilizziamo due tipi di vertice: Ebook
E Class
. Ogni entità è annotata usando le annotazioni Jakarta NoSQL e contiene un ID univoco e un nome. Queste entità costituiranno le basi del nostro grafico, permettendoci di definire le relazioni tra libri e le loro categorie affiliate.
@Entity
public class Ebook {
@Id
personal Lengthy id;
@Column
personal String identify;
}
@Entity
public class Class {
@Id
personal Lengthy id;
@Column
personal String identify;
}
Una volta particular le entità, il passo successivo è persistere e recuperarle dal database. A story scopo, Eclipse Jnosql fornisce il TinkerpopTemplate
che è una specializzazione del generico Template
Interfaccia appositamente progettata per le operazioni grafiche utilizzando Apache TinkerPop. Il livello di servizio incapsula la logica di interrogazione del database per libri o categorie esistenti e inserirne di nuovi se non esistono. Questo modello aiuta a mantenere l’idePemotenza quando si salva i dati, garantendo che non vengano creati duplicati.
@ApplicationScoped
public class BookService {
@Inject
personal TinkerpopTemplate template;
public Ebook save(Ebook ebook) {
return template.choose(Ebook.class).the place("identify").eq(ebook.getName()).singleResult()
.orElseGet(() -> template.insert(ebook));
}
public Class save(Class class) {
return template.choose(Class.class).the place("identify").eq(class.getName()).singleResult()
.orElseGet(() -> template.insert(class));
}
}
IL BookApp
La classe mostra l’esecuzione completa: inserire entità, creare relazioni (bordi) ed eseguire le question di Gremlin:
var architectureBooks = template.gremlin("g.V().hasLabel('Class').has('identify','Structure').in('is')").toList();
var highRelevanceBooks = template.gremlin("g.E().hasLabel('is').has('relevance', gte(9)).outV().hasLabel('Ebook').dedup()").toList();
Puoi anche fare catene di traversa con .traversalVertex()
Per pipeline più fluenti:
Checklist softwareBooks = template.traversalVertex().hasLabel("Class")
.has("identify", "Software program")
.in("is").hasLabel("Ebook").end result()
.map(Ebook::getName).toList();
IL BookApp
Introduce la capacità di TinkerPopTemplate, dove abbiamo il ponte tra Java e Janus Database:
public remaining class BookApp {
personal BookApp() {
}
public static void major(String() args) {
attempt (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
var template = container.choose(TinkerpopTemplate.class).get();
var service = container.choose(BookService.class).get();
var software program = service.save(Class.of("Software program"));
var java = service.save(Class.of("Java"));
var structure = service.save(Class.of("Structure"));
var efficiency = service.save(Class.of("Efficiency"));
var effectiveJava = service.save(Ebook.of("Efficient Java"));
var cleanArchitecture = service.save(Ebook.of("Clear Structure"));
var systemDesign = service.save(Ebook.of("System Design Interview"));
var javaPerformance = service.save(Ebook.of("Java Efficiency"));
template.edge(Edge.supply(effectiveJava).label("is").goal(java).property("relevance", 10).construct());
template.edge(Edge.supply(effectiveJava).label("is").goal(software program).property("relevance", 9).construct());
template.edge(Edge.supply(cleanArchitecture).label("is").goal(software program).property("relevance", 8).construct());
template.edge(Edge.supply(cleanArchitecture).label("is").goal(structure).property("relevance", 10).construct());
template.edge(Edge.supply(systemDesign).label("is").goal(structure).property("relevance", 9).construct());
template.edge(Edge.supply(systemDesign).label("is").goal(software program).property("relevance", 7).construct());
template.edge(Edge.supply(javaPerformance).label("is").goal(efficiency).property("relevance", 8).construct());
template.edge(Edge.supply(javaPerformance).label("is").goal(java).property("relevance", 9).construct());
Checklist softwareCategories = template.traversalVertex().hasLabel("Class")
.has("identify", "Software program")
.in("is").hasLabel("Class").end result()
.map(Class::getName)
.toList();
Checklist softwareBooks = template.traversalVertex().hasLabel("Class")
.has("identify", "Software program")
.in("is").hasLabel("Ebook").end result()
.map(Ebook::getName)
.toList();
Checklist sofwareNoSQLBooks = template.traversalVertex().hasLabel("Class")
.has("identify", "Software program")
.in("is")
.has("identify", "NoSQL")
.in("is").end result()
.map(Ebook::getName)
.toList();
System.out.println("The software program classes: " + softwareCategories);
System.out.println("The software program books: " + softwareBooks);
System.out.println("The software program and NoSQL books: " + sofwareNoSQLBooks);
System.out.println("Books in 'Structure' class:");
var architectureBooks = template.gremlin("g.V().hasLabel('Class').has('identify','Structure').in('is')").toList();
architectureBooks.forEach(doc -> System.out.println(" - " + doc));
System.out.println("Classes with a couple of ebook:");
var commonCategories = template.gremlin("g.V().hasLabel('Class').the place(__.in('is').depend().is(gt(1)))"
).toList();
commonCategories.forEach(doc -> System.out.println(" - " + doc));
var highRelevanceBooks = template.gremlin( "g.E().hasLabel('is').has('relevance', gte(9))" +
".outV().hasLabel('Ebook').dedup()").toList();
System.out.println("Books with excessive relevance:");
highRelevanceBooks.forEach(doc -> System.out.println(" - " + doc));
System.out.println("Books with identify: 'Efficient Java':");
var effectiveJavaBooks = template.gremlin("g.V().hasLabel('Ebook').has('identify', @identify)", Collections.singletonMap("identify", "Efficient Java")).toList();
effectiveJavaBooks.forEach(doc -> System.out.println(" - " + doc));
}
}
}
Per integrare l’uso di TinkerpopTemplate
Eclipse JNOSQL supporta le specifiche di dati Jakarta abilitando l’accesso ai dati basati sul repository. Questo approccio consente agli sviluppatori di definire le interfacce, come BookRepository
E CategoryRepository
– che forniscono automaticamente operazioni CRUD e supportano i traversari grafici personalizzati attraverso il @Gremlin
annotazione.
Combinando le question dei nomi del metodo commonplace (advert es. findByName
) Con gli script espressivi di Gremlin, otteniamo sia comodità che controllo a grana fantastic sulla logica di attraversamento del grafico. Questi repository sono ideali per i modelli di accesso puliti, verificabili e dichiarativi nelle applicazioni basate su grafici.
@Repository
public interface BookRepository extends TinkerPopRepository {
Elective findByName(String identify);
@Gremlin("g.V().hasLabel('Ebook').out('is').hasLabel('Class').has('identify','Structure').in('is').dedup()")
Checklist findArchitectureBooks();
@Gremlin("g.E().hasLabel('is').has('relevance', gte(9)).outV().hasLabel('Ebook').dedup()")
Checklist highRelevanceBooks();
}
@Repository
public interface CategoryRepository extends TinkerPopRepository {
Elective findByName(String identify);
@Gremlin("g.V().hasLabel('Class').the place(__.in('is').depend().is(gt(1)))")
Checklist commonCategories();
}
Dopo aver definito i repository, possiamo creare un’applicazione completa che li sfrutta per gestire i dati ed eseguire question. IL BookApp2
La classe illustra questo flusso di esecuzione basato sul repository. Utilizza i repository per creare o recuperare vertici (Ebook
E Class
) e ricade a GraphTemplate
Solo quando si inseriscono i bordi, poiché i dati di Jakarta attualmente supportano interrogare i vertici ma non la creazione di Edge. Questo modello ibrido fornisce una separazione pulita delle preoccupazioni e riduce la piastra della caldaia, rendendo più facile leggere, testare e mantenere.
public remaining class BookApp2 {
personal BookApp2() {
}
public static void major(String() args) {
attempt (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
var template = container.choose(GraphTemplate.class).get();
var bookRepository = container.choose(BookRepository.class).get();
var repository = container.choose(CategoryRepository.class).get();
var software program = repository.findByName("Software program").orElseGet(() -> repository.save(Class.of("Software program")));
var java = repository.findByName("Java").orElseGet(() -> repository.save(Class.of("Java")));
var structure = repository.findByName("Structure").orElseGet(() -> repository.save(Class.of("Structure")));
var efficiency = repository.findByName("Efficiency").orElseGet(() -> repository.save(Class.of("Efficiency")));
var effectiveJava = bookRepository.findByName("Efficient Java").orElseGet(() -> bookRepository.save(Ebook.of("Efficient Java")));
var cleanArchitecture = bookRepository.findByName("Clear Structure").orElseGet(() -> bookRepository.save(Ebook.of("Clear Structure")));
var systemDesign = bookRepository.findByName("System Design Interview").orElseGet(() -> bookRepository.save(Ebook.of("System Design Interview")));
var javaPerformance = bookRepository.findByName("Java Efficiency").orElseGet(() -> bookRepository.save(Ebook.of("Java Efficiency")));
template.edge(Edge.supply(effectiveJava).label("is").goal(java).property("relevance", 10).construct());
template.edge(Edge.supply(effectiveJava).label("is").goal(software program).property("relevance", 9).construct());
template.edge(Edge.supply(cleanArchitecture).label("is").goal(software program).property("relevance", 8).construct());
template.edge(Edge.supply(cleanArchitecture).label("is").goal(structure).property("relevance", 10).construct());
template.edge(Edge.supply(systemDesign).label("is").goal(structure).property("relevance", 9).construct());
template.edge(Edge.supply(systemDesign).label("is").goal(software program).property("relevance", 7).construct());
template.edge(Edge.supply(javaPerformance).label("is").goal(efficiency).property("relevance", 8).construct());
template.edge(Edge.supply(javaPerformance).label("is").goal(java).property("relevance", 9).construct());
System.out.println("Books in 'Structure' class:");
var architectureBooks = bookRepository.findArchitectureBooks();
architectureBooks.forEach(doc -> System.out.println(" - " + doc));
System.out.println("Classes with a couple of ebook:");
var commonCategories = repository.commonCategories();
commonCategories.forEach(doc -> System.out.println(" - " + doc));
var highRelevanceBooks = bookRepository.highRelevanceBooks();
System.out.println("Books with excessive relevance:");
highRelevanceBooks.forEach(doc -> System.out.println(" - " + doc));
var bookByName = bookRepository.queryByName("Efficient Java");
System.out.println("Ebook by identify: " + bookByName);
}
}
}
Janusgraph, sostenuta da Apache Tinkerpop e Gremlin, offre un modo altamente scalabile e portatile per modellare e attraversare grafici complessi. Con Eclipse JNOSQL e Jakarta Knowledge, gli sviluppatori di Java possono sfruttare potenti capacità grafiche mentre si godono un’API pulita e modulare. Janus si adatta alla tua architettura, incorporata o distribuita, mantenendo le domande espressive e concise.