Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hibernate und Elasticsearch - Von 0 auf 100 in 40 Minuten

Hibernate und Elasticsearch - Von 0 auf 100 in 40 Minuten

How to add full text search to Hibernate applications, using Elasticsearch. The talk was given at JavaLand 2017 (German).

Gunnar Morling

March 29, 2017
Tweet

More Decks by Gunnar Morling

Other Decks in Programming

Transcript

  1. Gunnar Morling Opensource-Softwareentwickler bei Red Hat Div. Hibernate-Projekte Spec Lead

    für Bean Validation 2.0 Andere Projekte: ModiTect, MapStruct [email protected] @gunnarmorling http://in.relation.to/gunnar-morling/ 2
  2. Wie umsetzen? SQL hat LIKE? SELECT * FROM PRODUCT p

    WHERE LOWERCASE(p.title) LIKE %:1% OR LOWERCASE(p.title) LIKE %:2% OR LOWERCASE(p.title) LIKE %:3% OR LOWERCASE(p.description) LIKE %:1% OR LOWERCASE(p.description) LIKE %:2% OR LOWERCASE(p.description) LIKE %:3% OR ... ; 4
  3. Wie umsetzen? Ja, aber... Flexionen, Normalisierung, Stop-Worte Synonyme, Abkürzungen Unscharfe

    Suche Ergebnissortierung SELECT * FROM PRODUCT p WHERE LOWERCASE(p.title) LIKE %:1% OR LOWERCASE(p.title) LIKE %:2% OR LOWERCASE(p.title) LIKE %:3% OR LOWERCASE(p.description) LIKE %:1% OR LOWERCASE(p.description) LIKE %:2% OR LOWERCASE(p.description) LIKE %:3% OR ... ; 6
  4. Wie umsetzen? Invertierter Index Text zerlegen ("tokenisation") Index erstellen: Token

    ˠ Enthaltende Dokumente Suche: Relevanzbasierte Sortierung 7
  5. Lucene + Elasticsearch Apache Lucene DIE Java-Library für Volltextsuche Feature-reich,

    anpassbar Hohe Performanz Elasticsearch "Search as a Service" Basiert auf Lucene Scale-out Architektur REST API 8
  6. Index-Synchronisation?! Indexstruktur synchron halten Update des Index in Elasticsearch bei

    Datenänderungen JSON erzeugen Typumwandlungen Assoziationen/Denormalisierungen Mapping von Suchergebnissen 10
  7. Hibernate Search Integriert Hibernate und Lucene Traditionell: Eigene Verwaltung des

    Lucene-Index Dateisystem Infinispan Unter Java SE and EE Kein neues Projekt :) 12
  8. Ein Beispiel persistence.xml <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1"> <persistence-unit name="videoGamePu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

    <properties> <property name="hibernate.connection.url" value="..." /> <property name="hibernate.search.default.indexmanager" value="elasticsearch" /> <property name="hibernate.search.default.elasticsearch.host" value="http://127.0.0.1:9200" /> <property name="h.s.default.elasticsearch.index_schema_management_strategy" value="CREATE" /> </properties> </persistence-unit> </persistence> 15.3
  9. Ein Beispiel Root-Entität @Entity @Indexed(index = "videogame") public class VideoGame

    { @Id @GeneratedValue public long id; @Field() public String title; @Field public String description; @Field public int rating; @Field(name="release") public Date publishingDate; ... } curl -v -XGET 'host/videogame/_search?pretty=true' \ -d '{ "query" : { "match_all" : {} } }' { ... "hits": [ { "_index": "videogame", "_type": "org.hibernate. ... .VideoGame", "_id": "5", "_score": 1.0, "_source": { "rating": 8, "release": "2005-12-04T23:00:00Z", "description": "The Samurai is...", "title": "Revenge of the Samurai" } }, ... ] } } 15.4
  10. Ein Beispiel Embeddable und ElementCollection @Entity @Indexed(index = "videogame") public

    class VideoGame { @ManyToOne @IndexedEmbedded public Publisher publisher; @ElementCollection @Field @IndexedEmbedded public List<String> tags; ... } { "rating": 8, "description": "The Samurai is mad and takes revenge", "release": "2005-12-04T23:00:00Z", "title": "Revenge of the Samurai", "tags": [ "action", "real-time", "anime" ], "publisher": { "name": "Samurai Games, Inc.", "address": "12 Main Road" } } @Entity public class Publisher { @Field public String name; @Field public String address; ... 15.5
  11. Ein Beispiel Eingebettete Assoziation @Entity @Indexed(index = "videogame") public class

    VideoGame { @ManyToMany @IndexedEmbedded public List<Character> characters; ... } { "rating": 5, "description": "7 Ninjas live in a castle", "release": "2007-04-06T22:00:00Z", "title": "Ninja Castle", "publisher": { "name": "Samurai Games, Inc.", "address": "12 Main Road" }, "characters": [ { "nickName": "Frank", "specialPower": "Sleeping" }, { "nickName": "Dash", "specialPower": "Running" }, { "nickName": "Luigi", "specialPower": "Plumbing" } ] } @Entity public class Character { @Field public String nickName; @Field public String specialPower; ... } 15.6
  12. Abfragen Hibernate Search Query DSL Weitere: wildcard, range, boolean, fuzzy,

    phrase, spatial FullTextQuery query = ftem.createFullTextQuery( qb.spatial() .onField( "location" ) .within( 100, Unit.KM ) .ofLatitude( 24.0d ) .andLongitude( 32.0d ) .createQuery(), Restaurant.class ); 16
  13. FullTextQuery query = ftem.createFullTextQuery( ElasticsearchQueries.fromJson( "{" + "'query': {" +

    "'bool' : {" + "'must' : [" + "{ 'match' : { 'title' : 'samurai' } }," + "{ 'match' : { 'publisher.name' : 'games' } }" + "]" + "} } }" ), VideoGame.class ); Native Abfragen JSON-Syntax 17
  14. Vorteile Date und Index synchron Sichere, automatische Index-Updates Automatisches Mapping

    JSON-Mapping Typkonvertierungen Transparente Denormalisierung Managed Entities aus Abfragen Gute Performance (Bulk-Requests) 19
  15. Vorteile Entkopplung Einfache Konfiguration mittels Annotationen Keine direkten Aufrufe des

    ES API nötig Einfacher Backendwechsel Entkopplung von Komponenten zur Laufzeit 20
  16. Status Tech Preview in Hibernate Search 5.6/5.7 Indexierung verschiedenster Feldtypen,

    Embeddables etc. Diverse Abfrage-Möglichkeiten Viele Tests der bestehenden Testsuite erfolgreich 22
  17. Nächste Schritte 5.8: Unterstützung für Elasticsearch 5 Feedback sammeln in

    5.x Hibernate Search 6 Abstraktion von Lucene in API und SPI Query DSL verallgemeinern 6.x: Solr-Unterstützung 23
  18. 25