Merge pull request #798 from honestica/elasticsearch-mapping

Elasticsearch mapping for Jpa Server
This commit is contained in:
James Agnew 2018-03-15 06:52:17 -04:00 committed by GitHub
commit 84e606cfe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 200 additions and 0 deletions

View File

@ -0,0 +1,23 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>3.2.0-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-jpaserver-elasticsearch</artifactId>
<packaging>jar</packaging>
<name>HAPI FHIR JPA Server - ElasticSearch Integration</name>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-elasticsearch</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
package ca.uhn.fhir.jpa.search;
import org.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionRegistryBuilder;
import org.hibernate.search.elasticsearch.analyzer.definition.spi.ElasticsearchAnalysisDefinitionProvider;
public class ElasticsearchMappingProvider implements ElasticsearchAnalysisDefinitionProvider {
@Override
public void register(ElasticsearchAnalysisDefinitionRegistryBuilder builder) {
builder.analyzer("autocompleteEdgeAnalyzer")
.withTokenizer("pattern_all")
.withTokenFilters("lowercase", "stop", "edgengram_3_50");
builder.tokenizer("pattern_all").type("pattern").param("pattern", "(.*)").param("group", "1");
builder.tokenFilter("edgengram_3_50")
.type("edgeNGram")
.param("min_gram", "3")
.param("max_gram", "50");
builder.analyzer("autocompletePhoneticAnalyzer")
.withTokenizer("standard")
.withTokenFilters("standard", "stop", "snowball_english", "phonetic_doublemetaphone");
builder.tokenFilter("phonetic_doublemetaphone")
.type("phonetic")
.param("encoder", "double_metaphone");
builder.tokenFilter("snowball_english").type("snowball").param("language", "English");
builder.analyzer("autocompleteNGramAnalyzer")
.withTokenizer("standard")
.withTokenFilters("word_delimiter", "lowercase", "ngram_3_20");
builder.tokenFilter("ngram_3_20")
.type("nGram")
.param("min_gram", "3")
.param("max_gram", "20");
builder.analyzer("standardAnalyzer").withTokenizer("standard").withTokenFilters("lowercase");
builder.analyzer("exactAnalyzer").withTokenizer("standard");
builder.analyzer("conceptParentPidsAnalyzer").withTokenizer("whitespace");
}
}

View File

@ -41,3 +41,17 @@ Use this command to start the container:
`docker run -d --name hapi-fhir-jpaserver-example -p 8080:8080 hapi-fhir/hapi-fhir-jpaserver-example`
Note: with this command data is persisted across container restarts, but not after removal of the container. Use a docker volume mapping on /var/lib/jetty/target to achieve this.
#### Using ElasticSearch as the search engine instead of the default Apache Lucene
1. Install ElasticSearch server and the phonetic plugin
* Download ElasticSearch from https://www.elastic.co/downloads/elasticsearch
* ```cd {your elasticsearch directory}```
* ```bin/plugin install analysis-phonetic```
* start ElasticSearch server: ```./bin/elasticsearch```
2. Replace configuration in web.xml
* replace the configuration class ```ca.uhn.fhir.jpa.demo.FhirServerConfig``` in web.xml by ```ca.uhn.fhir.jpa.demo.elasticsearch.FhirServerConfig```
3. Start server by runing: ```mvn jetty:run```
4. Limitations:
* Hibernate search are not compatible with all ElasticSearch version. If you are using Hibernate search: 5.6 or 5.7, the compatible ElasticSearch version is 2.0 - 2.4. If you are using Hibernate search: 5.8 or 5.9, the compatible ElasticSearch version is
2.0 - 5.6.
* Please check all the limitations in the reference documentation: https://docs.jboss.org/hibernate/search/5.7/reference/en-US/html_single/#elasticsearch-limitations before use the integration.

View File

@ -74,6 +74,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-elasticsearch</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>

View File

@ -0,0 +1,110 @@
package ca.uhn.fhir.jpa.demo.elasticsearch;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.ElasticsearchMappingProvider;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* This is the configuration file for the example server integrating the ElasticSearch engine.
*/
@Configuration
@EnableTransactionManagement()
public class FhirServerConfig extends BaseJavaConfigDstu3 {
/**
* Configure FHIR properties around the the JPA server via this bean
*/
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setAllowMultipleDelete(true);
return retVal;
}
/**
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
* directory called "jpaserver_derby_files".
*
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
*/
@Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
retVal.setUrl("jdbc:derby:directory:target/jpaserver_derby_files;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.jdbc.batch_size", "20");
extraProperties.put("hibernate.cache.use_query_cache", "false");
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
extraProperties.put("hibernate.cache.use_structured_entries", "false");
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
// the belowing properties are used for ElasticSearch integration
extraProperties.put("hibernate.search.elasticsearch.analyzer_definition_provider", ElasticsearchMappingProvider.class.getName());
extraProperties.put("hibernate.search.default.indexmanager", "elasticsearch");
extraProperties.put("hibernate.search.default.elasticsearch.host", "http://127.0.0.1:9200");
extraProperties.put("hibernate.search.default.elasticsearch.index_schema_management_strategy", "CREATE");
extraProperties.put("hibernate.search.default.elasticsearch.index_management_wait_timeout", "10000");
extraProperties.put("hibernate.search.default.elasticsearch.required_index_status", "yellow");
return extraProperties;
}
/**
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
*/
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor responseHighlighterInterceptor() {
ResponseHighlighterInterceptor retVal = new ResponseHighlighterInterceptor();
return retVal;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
SubscriptionsRequireManualActivationInterceptorDstu3 retVal = new SubscriptionsRequireManualActivationInterceptorDstu3();
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@ -958,6 +958,11 @@
<artifactId>hibernate-search-orm</artifactId>
<version>${hibernate_search_version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-elasticsearch</artifactId>
<version>${hibernate_search_version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
@ -1958,6 +1963,7 @@
<module>hapi-fhir-jaxrsserver-base</module>
<module>hapi-fhir-jaxrsserver-example</module>
<module>hapi-fhir-jpaserver-base</module>
<module>hapi-fhir-jpaserver-elasticsearch</module>
<module>hapi-fhir-jpaserver-example</module>
<module>restful-server-example</module>
<module>restful-server-example-test</module>