diff --git a/spring-data-elasticsearch/.classpath b/spring-data-elasticsearch/.classpath
new file mode 100644
index 0000000000..698778fef3
--- /dev/null
+++ b/spring-data-elasticsearch/.classpath
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-data-elasticsearch/.project b/spring-data-elasticsearch/.project
new file mode 100644
index 0000000000..09b9a781ed
--- /dev/null
+++ b/spring-data-elasticsearch/.project
@@ -0,0 +1,29 @@
+
+
+ spring-data-elasticsearch
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/spring-data-elasticsearch/README.md b/spring-data-elasticsearch/README.md
new file mode 100644
index 0000000000..0dae92e0e7
--- /dev/null
+++ b/spring-data-elasticsearch/README.md
@@ -0,0 +1,12 @@
+## Spring Data Elasticsearch
+
+### Build the Project with Tests Running
+```
+mvn clean install
+```
+
+### Run Tests Directly
+```
+mvn test
+```
+
diff --git a/spring-data-elasticsearch/pom.xml b/spring-data-elasticsearch/pom.xml
new file mode 100644
index 0000000000..7ac6dd0fcf
--- /dev/null
+++ b/spring-data-elasticsearch/pom.xml
@@ -0,0 +1,78 @@
+
+ 4.0.0
+
+ org.baeldung
+ spring-data-elasticsearch
+ 0.0.1-SNAPSHOT
+ jar
+
+ spring-data-elasticsearch
+
+
+ UTF-8
+ 1.3.2.RELEASE
+ 4.2.2.RELEASE
+ 4.11
+ 1.7.12
+ 1.1.3
+ 1.3.2.RELEASE
+
+
+
+
+ org.springframework
+ spring-core
+ ${org.springframework.version}
+
+
+ junit
+ junit-dep
+ ${junit.version}
+ test
+
+
+ org.springframework
+ spring-test
+ ${org.springframework.version}
+ test
+
+
+ org.springframework.data
+ spring-data-elasticsearch
+ ${elasticsearch.version}
+
+
+ org.slf4j
+ slf4j-api
+ ${org.slf4j.version}
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${org.slf4j.version}
+
+
+ org.slf4j
+ log4j-over-slf4j
+ ${org.slf4j.version}
+
+
+
+
+
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.8
+ 1.8
+
+
+
+
+
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/config/Config.java b/spring-data-elasticsearch/src/main/java/com/baeldung/config/Config.java
new file mode 100644
index 0000000000..eb65e38f65
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/config/Config.java
@@ -0,0 +1,53 @@
+package com.baeldung.config;
+
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.node.NodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
+import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
+import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+@Configuration
+@EnableElasticsearchRepositories(basePackages = "com.baeldung.dao")
+@ComponentScan(basePackages = {"com.baeldung.service"})
+public class Config {
+
+ private static Logger logger = LoggerFactory.getLogger(Config.class);
+
+ @Bean
+ public NodeBuilder nodeBuilder() {
+ return new NodeBuilder();
+ }
+
+ @Bean
+ public ElasticsearchOperations elasticsearchTemplate() {
+
+ try {
+ Path tmpDir = Files.createTempDirectory(Paths.get(System.getProperty("java.io.tmpdir")), "elasticsearch_data");
+
+ ImmutableSettings.Builder elasticsearchSettings = ImmutableSettings.settingsBuilder()
+ .put("http.enabled", "false")
+ .put("path.data", tmpDir.toAbsolutePath().toString());
+
+ logger.debug(tmpDir.toAbsolutePath().toString());
+
+ return new ElasticsearchTemplate(nodeBuilder()
+ .local(true)
+ .settings(elasticsearchSettings.build())
+ .node()
+ .client());
+ } catch (IOException ioex) {
+ logger.error("Cannot create temp dir", ioex);
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/dao/ArticleRepository.java b/spring-data-elasticsearch/src/main/java/com/baeldung/dao/ArticleRepository.java
new file mode 100644
index 0000000000..6ed86eff9b
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/dao/ArticleRepository.java
@@ -0,0 +1,16 @@
+package com.baeldung.dao;
+
+import com.baeldung.model.Article;
+import com.baeldung.model.Article;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.elasticsearch.annotations.Query;
+import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
+
+public interface ArticleRepository extends ElasticsearchRepository {
+
+ Page findByAuthorsName(String name, Pageable pageable);
+
+ @Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
+ Page findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
+}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/model/Article.java b/spring-data-elasticsearch/src/main/java/com/baeldung/model/Article.java
new file mode 100644
index 0000000000..17580ca0db
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/model/Article.java
@@ -0,0 +1,60 @@
+package com.baeldung.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldIndex;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+
+import java.util.List;
+
+@Document(indexName = "article", type = "article")
+public class Article {
+
+ @Id
+ private String id;
+ @Field(type = FieldType.String, index = FieldIndex.not_analyzed)
+ private String title;
+ @Field(type = FieldType.Nested)
+ private List authors;
+
+ public Article() {
+ }
+
+ public Article(String title) {
+ this.title = title;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public List getAuthors() {
+ return authors;
+ }
+
+ public void setAuthors(List authors) {
+ this.authors = authors;
+ }
+
+ @Override
+ public String toString() {
+ return "Article{" +
+ "id='" + id + '\'' +
+ ", title='" + title + '\'' +
+ ", authors=" + authors +
+ '}';
+ }
+}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/model/Author.java b/spring-data-elasticsearch/src/main/java/com/baeldung/model/Author.java
new file mode 100644
index 0000000000..09239efbe5
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/model/Author.java
@@ -0,0 +1,28 @@
+package com.baeldung.model;
+
+public class Author {
+
+ private String name;
+
+ public Author() {
+ }
+
+ public Author(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "Author{" +
+ "name='" + name + '\'' +
+ '}';
+ }
+}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleService.java b/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleService.java
new file mode 100644
index 0000000000..052e22c67d
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleService.java
@@ -0,0 +1,15 @@
+package com.baeldung.service;
+
+import com.baeldung.model.Article;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+public interface ArticleService {
+ Article save(Article article);
+ Article findOne(String id);
+ Iterable findAll();
+ Page findByAuthorName(String name, Pageable pageable);
+ Page findByAuthorNameUsingCustomQuery(String name, Pageable pageable);
+ long count();
+ void delete(Article article);
+}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleServiceImpl.java b/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleServiceImpl.java
new file mode 100644
index 0000000000..4dc100ec22
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/service/ArticleServiceImpl.java
@@ -0,0 +1,54 @@
+package com.baeldung.service;
+
+import com.baeldung.dao.ArticleRepository;
+import com.baeldung.model.Article;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ArticleServiceImpl implements ArticleService {
+
+ private ArticleRepository articleRepository;
+
+ @Autowired
+ public void setArticleRepository(ArticleRepository articleRepository) {
+ this.articleRepository = articleRepository;
+ }
+
+ @Override
+ public Article save(Article article) {
+ return articleRepository.save(article);
+ }
+
+ @Override
+ public Article findOne(String id) {
+ return articleRepository.findOne(id);
+ }
+
+ @Override
+ public Iterable findAll() {
+ return articleRepository.findAll();
+ }
+
+ @Override
+ public Page findByAuthorName(String name, Pageable pageable) {
+ return articleRepository.findByAuthorsName(name, pageable);
+ }
+
+ @Override
+ public Page findByAuthorNameUsingCustomQuery(String name, Pageable pageable) {
+ return articleRepository.findByAuthorsNameUsingCustomQuery(name, pageable);
+ }
+
+ @Override
+ public long count() {
+ return articleRepository.count();
+ }
+
+ @Override
+ public void delete(Article article) {
+ articleRepository.delete(article);
+ }
+}
diff --git a/spring-data-elasticsearch/src/main/resources/logback.xml b/spring-data-elasticsearch/src/main/resources/logback.xml
new file mode 100644
index 0000000000..37a9e2edbf
--- /dev/null
+++ b/spring-data-elasticsearch/src/main/resources/logback.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ elasticsearch - %date [%thread] %-5level %logger{36} - %message%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-data-elasticsearch/src/test/java/com/baeldung/ElasticSearchTest.java b/spring-data-elasticsearch/src/test/java/com/baeldung/ElasticSearchTest.java
new file mode 100644
index 0000000000..07248149c2
--- /dev/null
+++ b/spring-data-elasticsearch/src/test/java/com/baeldung/ElasticSearchTest.java
@@ -0,0 +1,130 @@
+package com.baeldung;
+
+import com.baeldung.config.Config;
+import com.baeldung.model.Article;
+import com.baeldung.model.Author;
+import com.baeldung.service.ArticleService;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
+import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
+import org.springframework.data.elasticsearch.core.query.SearchQuery;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.elasticsearch.index.query.FilterBuilders.regexpFilter;
+import static org.elasticsearch.index.query.QueryBuilders.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {Config.class}, loader = AnnotationConfigContextLoader.class)
+public class ElasticSearchTest {
+
+ @Autowired
+ private ElasticsearchTemplate elasticsearchTemplate;
+ @Autowired
+ private ArticleService articleService;
+
+ private final Author johnSmith = new Author("John Smith");
+ private final Author johnDoe = new Author("John Doe");
+
+ @Before
+ public void before() {
+ elasticsearchTemplate.deleteIndex(Article.class);
+ elasticsearchTemplate.createIndex(Article.class);
+
+ Article article = new Article("Spring Data Elasticsearch");
+ article.setAuthors(asList(johnSmith, johnDoe));
+ articleService.save(article);
+
+ article = new Article("Search engines");
+ article.setAuthors(asList(johnDoe));
+ articleService.save(article);
+
+ article = new Article("Second Article About Elasticsearch");
+ article.setAuthors(asList(johnSmith));
+ articleService.save(article);
+ }
+
+ @Test
+ public void givenArticleService_whenSaveArticle_thenIdIsAssigned() {
+ List authors = asList(
+ new Author("John Smith"), johnDoe);
+
+ Article article = new Article("Making Search Elastic");
+ article.setAuthors(authors);
+
+ article = articleService.save(article);
+ assertNotNull(article.getId());
+ }
+
+ @Test
+ public void givenPersistedArticles_whenSearchByAuthorsName_thenRightFound() {
+
+ Page articleByAuthorName = articleService.findByAuthorName(johnSmith.getName(), new PageRequest(0, 10));
+ assertEquals(2L, articleByAuthorName.getTotalElements());
+ }
+
+ @Test
+ public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() {
+
+ Page articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10));
+ assertEquals(3L, articleByAuthorName.getTotalElements());
+ }
+
+
+ @Test
+ public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() {
+
+ SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withFilter(regexpFilter("title", ".*data.*"))
+ .build();
+ List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
+
+ assertEquals(1, articles.size());
+ }
+
+ @Test
+ public void givenSavedDoc_whenTitleUpdated_thenCouldFindByUpdatedTitle() {
+ SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(fuzzyQuery("title", "serch"))
+ .build();
+ List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
+
+ assertEquals(1, articles.size());
+
+ Article article = articles.get(0);
+ final String newTitle = "Getting started with Search Engines";
+ article.setTitle(newTitle);
+ articleService.save(article);
+
+ assertEquals(newTitle, articleService.findOne(article.getId()).getTitle());
+ }
+
+ @Test
+ public void givenSavedDoc_whenDelete_thenRemovedFromIndex() {
+
+ final String articleTitle = "Spring Data Elasticsearch";
+
+ SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%"))
+ .build();
+ List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
+ assertEquals(1, articles.size());
+ final long count = articleService.count();
+
+ articleService.delete(articles.get(0));
+
+ assertEquals(count - 1, articleService.count());
+ }
+}