no-hql at jug milano

67
NoHQL: oltre Hibernate e i database relazionali Java Users Group Milano 4 Novembre 2010 Sanne Grinovero Team Hibernate, Sourcesense Tristan Tarrant Freelance consultant

Upload: sanne-grinovero

Post on 15-Jul-2015

769 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: NO-HQL at JUG Milano

NoHQL: oltre Hibernate e i database relazionali

Java Users Group Milano4 Novembre 2010

Sanne GrinoveroTeam Hibernate, Sourcesense

Tristan TarrantFreelance consultant

Page 2: NO-HQL at JUG Milano

● Consulente presso Sourcesense e Red Hat● sviluppatore di Scarlet, clustering for JIRA● Consulente JBoss e Search (Lucene)

● Team Hibernate● Contributi open source:

● Apache Lucene/Solr● Infinispan● JGroups● Seam

chi sono?

Page 3: NO-HQL at JUG Milano

● Il problema● Lucene e integrazione tramite Hibernate

Search● Infinispan, in breve

● Infinispan Query● Hibernate Search con Infinispan

● Custom stores: Cassandra● Hibernate OGM

Agenda

Page 4: NO-HQL at JUG Milano

Search engine

● Chi cerca non sa cosa sta cercando:● non è in grado di inserire l'ID dell'oggetto che si

desidera recuperare● non conosce il contenuto esatto del documento

● Interfaccia tipica:● Form complesse con molti campi● Testo libero

Page 5: NO-HQL at JUG Milano

Esempio di modello (Hibernate)

Page 6: NO-HQL at JUG Milano

Una prima implementazione:

Page 7: NO-HQL at JUG Milano

Funziona?

String nomeAutore = “Fabrizio De André”String nomeProdotto = “Nuvole barocche”List<Prodotti> list = s.createQuery( “ ...? “ );

String nomeAutore = “De André, Fabrizio”String nomeProdotto = “Nuvole barocche”List<Prodotti> list = s.createQuery( “ ...? “ );

String nomeAutore = “De Andre, Fabrizio”String nomeProdotto = “Nuvole barocche”List<Prodotti> list = s.createQuery( “ ...? “ );

Page 8: NO-HQL at JUG Milano

Nuove feature richieste

● Campo unico● Nome autore e/o nome prodotto● Nome e cognome dell'autore, nomi composti

● Rilevanza● prodotti che corrispondono sia per nome che per

nome autore devono venire per primi● Nomi completi di prodotto prima di nomi parziali

– “portatili mac” > 1 - portatile mac2 - portatili

Page 9: NO-HQL at JUG Milano

SQL è il martello:

List<Prodotti> list = s.createQuery(“ ...? “).setParameter(“F. de André nuvole barocche”).list();

● case misto● posizione relativa dei termini● accenti e abbreviazioni● match su field multipli (titolo e autore)● 18,800 risultati in 0,41 secondi

Page 10: NO-HQL at JUG Milano

altre funzioni utili:

● Similitudine:● hibernate ~ hybernat

● Prossimità, sinonimi, abbreviazioni:● 'JPA' o 'Java Persistence API'

● Aggiustamenti nella rilevanza:● Un termine nel titolo “vale” di più?

● Stemming (per lingua!)

Page 11: NO-HQL at JUG Milano

Quanto userestiGoogle

se ti restituisse i siti in ordine alfabetico?

Page 12: NO-HQL at JUG Milano

Quanto userestiGoogle

se ti restituisse i siti in ordine alfabetico?

“hibernate”About 8,320,000 results (0.10 seconds)

Page 13: NO-HQL at JUG Milano

quindi..● Il database non è sufficiente

● SQL non è adatto a certi problemi● eppure SQL è tutt'ora molto utile

● Bisogna conoscere più strumenti per sceglere quelli giusti● database relazionali● filesystem● motori di indicizzazione fulltext● key-value store

● Integrare, mantenere coerenza e integrità dei dati● quanto basta

Page 14: NO-HQL at JUG Milano

Esempi di prodotti

Nexus

Page 15: NO-HQL at JUG Milano

Tipi di form e di search

Page 16: NO-HQL at JUG Milano

inverted index: Lucene

● Progetto open source Apache™,● nella “top 10” dei più scaricati.● Community molto attiva.

● Un'implementazione di indice invertito all'avanguaria, costantemente aggiornato allo stato dell'arte del settore.

● Principalmente in Java ma portato in vari altri linguaggi.● Si trovano innumerevoli estensioni open source, ad

esempio per il supporto ottimale di tutte le lingue occidentali.

Page 17: NO-HQL at JUG Milano

Lucene

● Similitudine tra termini e documenti● Sinonimi● Stemming● Stopwords● TermVectors● MoreLikeThis● Faceted Search● Velocità e scalabilità orizzontale

● ... e naturalmente ricerche full-text.

Page 18: NO-HQL at JUG Milano

Similitudine

● N-Grams (distanza di editing)● Fonetico (Soundex™)● Altro... definibile secondo necessità

Cagliari ⁓ càliariCagliari ⁓ cag agl gli lia ari

Cagliari ⁓ CGRI

Page 19: NO-HQL at JUG Milano

Lucene: Sinonimi (o quasi)

● Applicabile a “index time”● a “query time”● Necessita di un vocabolario● Integrabile con vari vocabolari (WordNet)

giornale ⁓ periodico ⁓ quotidiano

Page 20: NO-HQL at JUG Milano

Lucene: Stemming

In varie lingue!

parliamone ⁓ parloVelocemente ⁓ velocità

Page 21: NO-HQL at JUG Milano

Lucene: Stopwords

● Rimuovono “rumore di fondo” e termini di disturbo dall'indice: una ricerca per “non e queste al per da” non da indizi su cosa l'utente stia cercando.

Page 22: NO-HQL at JUG Milano

Lucene: Indice

● Necessita di un indice● Su disco● In memoria● ...

● Formato da elementi immutabili● Ottimizza la ricerca, non la modifica

● Un mondo fatto di stringhe e frequenze

Page 23: NO-HQL at JUG Milano

Può sembrare facile

● La struttura di un indice è profondamente diversa da un modello relazionale.

● L'indice e il database devono rimanere in coerenza, immediata o eventuale.● In caso di incoerenza: di quale vi fidate?

● Cosa restituiscono le query?● Come sono fatte le query?

Page 24: NO-HQL at JUG Milano

Strutture differenti per natura

● Un Documento Lucene, risultato di una query fulltext, assomiglia (vagamente) ad una

Map<String,String>

● Un modello Hibernate è composto da entità strutturate, è designato per essere funzionale come business model.

● I valori di ritorno di Query JPA/Hibernate sono gestiti dal persistence manager: modifiche sincronizzate al commit

● Si devono mappare dati strutturalmente diversi.

Page 25: NO-HQL at JUG Milano

Differenze strutturali dell'informazione

Page 26: NO-HQL at JUG Milano

Incoerenze architetturali

Page 27: NO-HQL at JUG Milano
Page 28: NO-HQL at JUG Milano

Quickstart su Hibernate Search

● Aggiungere hibernate-search al classpath e dipendenze<dependency>

   <groupId>org.hibernate</groupId>

   <artifactId>hibernate­search</artifactId>

   <version>3.2.0.Final</version>

</dependency>

● Il resto è opzionale:

● Dove mettere l'indice● Estensioni● Parametri per le performance● Mapping più sofisticati● Clustering

Page 29: NO-HQL at JUG Milano

Come usare Hibernate Search@Entitypublic class Essay {   @Id   public Long getId() { return id; }

   public String getSummary() { return summary; }   @Lob    public String getText() { return text; }   @ManyToOne    public Author getAuthor() { return author; }...

Page 30: NO-HQL at JUG Milano

Come usare Hibernate Search@Entity @Indexedpublic class Essay {   @Id   public Long getId() { return id; }

   public String getSummary() { return summary; }   @Lob    public String getText() { return text; }   @ManyToOne    public Author getAuthor() { return author; }...

Page 31: NO-HQL at JUG Milano

Come usare Hibernate Search@Entity @Indexedpublic class Essay {   @Id   public Long getId() { return id; }   @Field   public String getSummary() { return summary; }   @Lob    public String getText() { return text; }   @ManyToOne    public Author getAuthor() { return author; }...

Page 32: NO-HQL at JUG Milano

Come usare Hibernate Search@Entity @Indexedpublic class Essay {   @Id   public Long getId() { return id; }   @Field   public String getSummary() { return summary; }   @Lob @Field @Boost(0.8)   public String getText() { return text; }   @ManyToOne    public Author getAuthor() { return author; }...

Page 33: NO-HQL at JUG Milano

Come usare Hibernate Search@Entity @Indexedpublic class Essay {   @Id   public Long getId() { return id; }   @Field   public String getSummary() { return summary; }   @Lob @Field @Boost(0.8)   public String getText() { return text; }   @ManyToOne @IndexedEmbedded    public Author getAuthor() { return author; }...

Page 34: NO-HQL at JUG Milano

@Entitypublic class Author {

@Id @GeneratedValueprivate Integer id;private String name;@OneToManyprivate Set<Book> books;

}

@Entitypublic class Book { private Integer id; private String title;}

Altro esempio

Page 35: NO-HQL at JUG Milano

@Entity @Indexedpublic class Author {

@Id @GeneratedValueprivate Integer id;

@Field(store=Store.YES)

private String name;@OneToMany

@IndexedEmbeddedprivate Set<Book> books;

}

@Entitypublic class Book { private Integer id; @Field(store=Store.YES) private String title;}

Struttura dell'indice

Page 36: NO-HQL at JUG Milano

String[] productFields = {"summary", "author.name"};

QueryParser parser = new MultiFieldQueryParser(productFields,   new StandardAnalyzer() );

Query luceneQuery = parser.parse(searchQuery);

FullTextEntityManager ftEm =   Search.getFullTextEntityManager(entityManager);

FullTextQuery query =   ftEm.createFullTextQuery(luceneQuery,Product.class );

List<Essay> items = query.setMaxResults(100).getResultList();

int totalNbrOfResults = query.getResultSize();

Codice di Query:

TotalNbrOfResults= 8.320.000(0.20 seconds)

Page 37: NO-HQL at JUG Milano

Risultati

● Pojo gestiti: coerenza tra le tecnologie di store● Paginazione JPA

● .setMaxResults( 20 ).setFirstResult( 100 );

● Restrizioni per tipo e polimorfismo:● .createQuery( luceneQuery, A.class, B.class, ..);

● Projection● Result mapping

Page 38: NO-HQL at JUG Milano

Filtri

FullTextQuery ftQuery = s // s è di tipo FullTextSession

   .createFullTextQuery( query, Prodotto.class )

   .enableFullTextFilter( "vietatoMinori" )

   .enableFullTextFilter( "offerteDelGiorno" )

      .setParameter( "giorno", “20101104” )

   .enableFullTextFilter( "disponibiliSubito" )

      .setParameter( "sede", "Milano" );

List<Prodotto> risultati = ftQuery.list();

Page 39: NO-HQL at JUG Milano
Page 40: NO-HQL at JUG Milano

Analisi del testo@Entity @Indexed

@AnalyzerDef(name = "italianAnalyzer", tokenizer =    

  @TokenizerDef(factory=StandardTokenizerFactory.class),filters = {

     @TokenFilterDef(factory = LowerCaseFilterFactory.class),

     @TokenFilterDef(factory = SnowballPorterFilterFactory.class,

         params = {@Parameter(name = "language", value = "Italian")})

})

public class Book {

   @Field(index=Index.TOKENIZED, store=Store.NO)

   @Analyzer(definition = "italianAnalyzer")

   private String title;

   ...

Page 41: NO-HQL at JUG Milano

Altro...

● @Boost e @DynamicBoost● @AnalyzerDiscriminator● @DateBridge(resolution=Resolution.MINUTE)● @ClassBridge e @FieldBridge● @Similarity● Automatic Index optimization

Page 42: NO-HQL at JUG Milano

Clustering per coda

Page 43: NO-HQL at JUG Milano

Attualmente in beta:

● Astrazione delle query Lucene● Performance migliorate

● Lucene 3● NumericField● FieldCache

● Mapping dinamico

● Infinispan clustering

Page 44: NO-HQL at JUG Milano

cos'è Infinispan? Perchè?

● Highly scalable data grid platform● 100% open source licensed (LGPL)● Based on some JBoss Cache code

● But mostly all-new!

● JBoss Cache is a clustered caching library● Infinispan is a data grid platform

● JBoss Cache uses a tree-structured API● Infinispan is a Map. Like JSR-107’s JCACHE

Page 45: NO-HQL at JUG Milano

Data Storage

● Le cloud sono di natura effimera● appliance più affidabili sono stateless

● Database difficili da gestire● MySQL in cluster.. ! solo con RDS

● Scalabilità in cloud: importante?● Database sono ancora un collo di bottiglia

● e single point of failure!

Page 46: NO-HQL at JUG Milano

Soluzione: data grids!

● Altamente scalabili● no single point of failure● funziona con nodi effimeri● latenza minima

● Implementazioni● Amazon SimpleDB / Dynamo● Infinispan● altri...

Page 47: NO-HQL at JUG Milano

Complicato?

Page 48: NO-HQL at JUG Milano

Tutti conoscono Map<?,?>

CacheManager cm = new DefaultCacheManager("infin-cfg.xml");Cache cache1 = cm.getCache("cache1");

Map distMap = cache1;distMap.put( "chiave", "valore" );distMap.get( "altraChiave" );

ConcurrentMap concurrentDistMap = cm.getCache("cache2");concurrentDistMap.replace( "k", "atteso", "nuovo" );

Page 49: NO-HQL at JUG Milano

Map, arricchito

CacheManager cm = new DefaultCacheManager("infi-cfg.xml");Cache cache1 = cm.getCache("cache1");

cache1.addListener( arg0 );

cache1.putAsync( arg0, arg1 );cache1.removeAsync( arg0 );

cache1.startBatch();

AdvancedCache advancedCache = cache1.getAdvancedCache();advancedCache.withFlags( Flag.SKIP_REMOTE_LOOKUP ) .put( arg0, arg1 );

Page 50: NO-HQL at JUG Milano

Caratteristiche

● Strutture interne efficienti● CAS totale● Synchronized assente● Contenitori di dati naturalmete ordinate

– Molto efficiente per gestire policy di eviction

● Serializzazione ottimizzata● JBoss Marshalling

– payloads minimali + poolable streams

Page 51: NO-HQL at JUG Milano

Ereditati da JBoss Cache

● JTA transactions● Replicated data structure● Eviction● Notifications and eventing API● JMX reporting● Fine-grained replication● MVCC locking● Non-blocking state transfer techniques

● CacheStore API● Custom (non-JDK) marshalling

Page 52: NO-HQL at JUG Milano

Nuove caratteristiche di Infinispan

● Cache distribuita: Consistent hash based data distribution

● Map API semplicissima (JSR-107 compliant)● Non limitato ai linguaggi JVM

● REST API● modulo compatibile memcached Client/server● HotRod (es: Java, Ruby, Python, ...)

● Plugin di management per JOPR● Distributed executors

● Query API

Page 53: NO-HQL at JUG Milano

Cache distribuita

● Consistent hash based data distribution● Permette di scalare su cluster grandi● Test in corso su cluster di migliaia di nodi

● Cache locale “L1” per letture migliorate● Invalidazione distribuita

● Ribilanciamento dinamico● Non presenta single-point-of-failure

Page 54: NO-HQL at JUG Milano

Memoria condivisa, Indice condiviso

Page 55: NO-HQL at JUG Milano

Vari CacheStore

● Filesystem● Database SQL● S3 / jclouds● Jdbm● ...

Page 56: NO-HQL at JUG Milano

Storage esterno, copie locali

Page 57: NO-HQL at JUG Milano

Clustering, store condiviso

Page 58: NO-HQL at JUG Milano

Vari CacheStore

● Filesystem● Database SQL● S3 / jclouds● Jdbm●

Page 59: NO-HQL at JUG Milano

...in conclusione con Infinispan

● query full text in memoria distribuita● cache distribuita, evict to “slow” CacheStore

● usa quella adatta all'uso!

● Infinispan: Hibernate Second level cache● usa anche i database, con caching (Not-Only SQL)

● Indicizza gli oggetti anche senza database● Infinispan Query● Query distribute (map/reduce, non full text)

● ogni componente prende parte a XA● eppur scala!

Page 60: NO-HQL at JUG Milano
Page 61: NO-HQL at JUG Milano
Page 62: NO-HQL at JUG Milano
Page 63: NO-HQL at JUG Milano
Page 64: NO-HQL at JUG Milano
Page 65: NO-HQL at JUG Milano

In conclusione● Integrità e transazioni

● infinispan supporta transazioni XA– e ne fornisce i vantaggi poggiando su store “unaware”

● Hibernate Search offre transazioni su Lucene

● efficienza: strategie ottimali per ogni query● monitoring

● enterprise level● statistiche

● scalabilità orizzontale

open source: partecipa!

Page 66: NO-HQL at JUG Milano

Quale approccio è più complesso?Quale funziona?

@Entity @Indexedpublic class Essay {      @Id   public Long getId() { return id; }      @Field   public String getSummary() {return summary; }      @ManyToOne @IndexedEmbedded    public Author getAuthor() { return author; }

Tecnologie già note

Codice costoso da refattorizzareNon scalaSolo i requisiti più semplici sono fattibili

Velocissimo e scalabileFunziona anche per rilevanzaSemplice evolvere il modello

Utile conoscere i fondamenti di Lucene

Page 67: NO-HQL at JUG Milano

Domande?

http://search.hibernate.org● Hibernate Search in Action

http://lucene.apache.org● Lucene In Action (2°ed)

http://www.infinispan.org

http://in.relation.to

http://forum.hibernate.org

twitter.com/SanneGrinovero

http://www.sourcesense.com