- 创建工程,导入坐标
- 创建索引 index
- 创建映射 mapping
- 建立文档 document
- 建立文档(通过 XContentBuilder)
- 建立文档(使用 Jackson 转换实体)
- 1)添加jackson坐标
- 2)创建 Article 实体
- 3)代码实现
- 查询文档操作
- 关键词查询
- 字符串查询
- 使用文档 ID 查询文档
- 查询文档分页操作
- 批量插入数据
- 分页查询
- 查询结果高亮操作
- 高亮显示的 html 分析
- 高亮显示代码实现
- Spring Data ElasticSearch
- Spring Data
- Spring Data ElasticSearch
- SpringMvc
- 1)导入 Spring Data ElasticSearch 坐标
- 2)创建 applicationContext.xml 配置文件,引入 elasticsearch 命名空间
- 3)编写实体 Article
- 4)编写 Dao
- 5)编写 Service
- 6) 配置 applicationContext.xml
- 7)配置实体
- 8)创建测试类 SpringDataESTest
- SpringBoot
- 1)添加 maven 依赖
- 2)配置 application.properties
- 3)测试实体类
- 方式一:继承 ElasticsearchRepository(适合简单查询)
- 添加单个文档
- 想自定义自己的 Repository 接口
- 方式二:使用 ElasticsearchRestTemplate(更适合用于复杂查询)
- 添加单个文档
- 简单查询-通过 id
- 方式一:继承 ElasticsearchRepository(适合简单查询)
- 常用查询命名规则
- 查询方法测试
- 1)dao 层实现
- 2)service 层实现
- 3)测试代码
- 使用 Elasticsearch 的原生查询对象进行查询。
- SpringMvc
创建工程,导入坐标
pom.xml坐标
<dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>5.6.8</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>5.6.8</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.9.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.24</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.21</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>
</dependencies>
创建索引 index
@Test
//创建索引
public void test1() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));//创建名称为blog2的索引client.admin().indices().prepareCreate("blog2").get();//释放资源client.close();
}
创建映射 mapping
@Test
//创建映射
public void test3() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));// 添加映射/*** 格式:* "mappings" : {"article" : {"dynamic" : "false","properties" : {"id" : { "type" : "string" },"content" : { "type" : "string" },"author" : { "type" : "string" }}}}*/XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject("article").startObject("properties").startObject("id").field("type", "integer").field("store", "yes").endObject().startObject("title").field("type", "string").field("store", "yes").field("analyzer", "ik_smart").endObject().startObject("content").field("type", "string").field("store", "yes").field("analyzer", "ik_smart").endObject().endObject().endObject().endObject();// 创建映射PutMappingRequest mapping = Requests.putMappingRequest("blog2").type("article").source(builder);client.admin().indices().putMapping(mapping).get();//释放资源client.close();
}
建立文档 document
建立文档(通过 XContentBuilder)
@Test
//创建文档(通过XContentBuilder)
public void test4() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));//创建文档信息XContentBuilder builder = XContentFactory.jsonBuilder().startObject().field("id", 1).field("title", "ElasticSearch是一个基于Lucene的搜索服务器").field("content","它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。").endObject();// 建立文档对象/*** 参数一blog1:表示索引对象* 参数二article:类型* 参数三1:建立id*/client.prepareIndex("blog2", "article", "1").setSource(builder).get();//释放资源client.close();
}
建立文档(使用 Jackson 转换实体)
1)添加jackson坐标
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.8.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.1</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.8.1</version>
</dependency>
2)创建 Article 实体
public class Article {private Integer id;private String title;private String content;getter/setter...
}
3)代码实现
@Test
//创建文档(通过实体转json)
public void test5() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));// 描述json 数据//{id:xxx, title:xxx, content:xxx}Article article = new Article();article.setId(2);article.setTitle("搜索工作其实很快乐");article.setContent("我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");ObjectMapper objectMapper = new ObjectMapper();// 建立文档client.prepareIndex("blog2", "article", article.getId().toString())//.setSource(objectMapper.writeValueAsString(article)).get();.setSource(objectMapper.writeValueAsString(article).getBytes(), XContentType.JSON).get();//释放资源client.close();
}
查询文档操作
关键词查询
@Test
public void testTermQuery() throws Exception{//1、创建es客户端连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));//2、设置搜索条件SearchResponse searchResponse = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.termQuery("content", "搜索")).get();//3、遍历搜索结果数据SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象System.out.println("查询结果有:" + hits.getTotalHits() + "条");Iterator<SearchHit> iterator = hits.iterator();while (iterator.hasNext()) {SearchHit searchHit = iterator.next(); // 每个查询对象System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印System.out.println("title:" + searchHit.getSource().get("title"));}//4、释放资源client.close();}
字符串查询
@Test
public void testStringQuery() throws Exception{//1、创建es客户端连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));//2、设置搜索条件SearchResponse searchResponse = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.queryStringQuery("搜索")).get();//3、遍历搜索结果数据SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象System.out.println("查询结果有:" + hits.getTotalHits() + "条");Iterator<SearchHit> iterator = hits.iterator();while (iterator.hasNext()) {SearchHit searchHit = iterator.next(); // 每个查询对象System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印System.out.println("title:" + searchHit.getSource().get("title"));}//4、释放资源client.close();}
使用文档 ID 查询文档
@Testpublic void testIdQuery() throws Exception {//client对象为TransportClient对象SearchResponse response = client.prepareSearch("blog1").setTypes("article")//设置要查询的id.setQuery(QueryBuilders.idsQuery().addIds("test002"))//执行查询.get();//取查询结果SearchHits searchHits = response.getHits();//取查询结果总记录数System.out.println(searchHits.getTotalHits());Iterator<SearchHit> hitIterator = searchHits.iterator();while(hitIterator.hasNext()) {SearchHit searchHit = hitIterator.next();//打印整行数据System.out.println(searchHit.getSourceAsString());}}
查询文档分页操作
批量插入数据
@Test
//批量插入100条数据
public void test9() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));ObjectMapper objectMapper = new ObjectMapper();for (int i = 1; i <= 100; i++) {// 描述json 数据Article article = new Article();article.setId(i);article.setTitle(i + "搜索工作其实很快乐");article.setContent(i+ "我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");// 建立文档client.prepareIndex("blog2", "article", article.getId().toString())//.setSource(objectMapper.writeValueAsString(article)).get();.setSource(objectMapper.writeValueAsString(article).getBytes(),XContentType.JSON).get();}//释放资源client.close();
}
分页查询
@Test
//分页查询
public void test10() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));// 搜索数据SearchRequestBuilder searchRequestBuilder = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.matchAllQuery());//默认每页10条记录// 查询第2页数据,每页20条//setFrom():从第几条开始检索,默认是0。//setSize():每页最多显示的记录数。searchRequestBuilder.setFrom(0).setSize(5);SearchResponse searchResponse = searchRequestBuilder.get();SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象System.out.println("查询结果有:" + hits.getTotalHits() + "条");Iterator<SearchHit> iterator = hits.iterator();while (iterator.hasNext()) {SearchHit searchHit = iterator.next(); // 每个查询对象System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印System.out.println("id:" + searchHit.getSource().get("id"));System.out.println("title:" + searchHit.getSource().get("title"));System.out.println("content:" + searchHit.getSource().get("content"));System.out.println("-----------------------------------------");}//释放资源client.close();
}
查询结果高亮操作
在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮
高亮显示的 html 分析
通过开发者工具查看高亮数据的 html 代码实现:
ElasticSearch 可以对查询出的内容中关键字部分进行标签和样式的设置,但是你需要告诉ElasticSearch 使用什么标签对高亮关键字进行包裹
高亮显示代码实现
@Test
//高亮查询
public void test11() throws Exception{// 创建Client连接对象Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));// 搜索数据SearchRequestBuilder searchRequestBuilder = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.termQuery("title", "搜索"));//设置高亮数据HighlightBuilder hiBuilder=new HighlightBuilder();hiBuilder.preTags("<font style='color:red'>");hiBuilder.postTags("</font>");hiBuilder.field("title");searchRequestBuilder.highlighter(hiBuilder);//获得查询结果数据SearchResponse searchResponse = searchRequestBuilder.get();//获取查询结果集SearchHits searchHits = searchResponse.getHits();System.out.println("共搜到:"+searchHits.getTotalHits()+"条结果!");//遍历结果for(SearchHit hit:searchHits){System.out.println("String方式打印文档搜索内容:");System.out.println(hit.getSourceAsString());System.out.println("Map方式打印高亮内容");System.out.println(hit.getHighlightFields());System.out.println("遍历高亮集合,打印高亮片段:");Text[] text = hit.getHighlightFields().get("title").getFragments();for (Text str : text) {System.out.println(str);}}//释放资源client.close();
}
Spring Data ElasticSearch
Spring Data
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。
Spring Data的官网:http://projects.spring.io/spring-data/
Spring Data常用的功能模块如下:
Spring Data ElasticSearch
Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 。Spring Data为Elasticsearch项目提供集成搜索引擎。Spring Data Elasticsearch POJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储库数据访问层。
官方网站:http://projects.spring.io/spring-data-elasticsearch/
SpringMvc
1)导入 Spring Data ElasticSearch 坐标
<?xml version="1.0" encoding="UTF-8"?>
<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><groupId>com.itheima</groupId><artifactId>itheima_elasticsearch_demo3</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>5.6.8</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>5.6.8</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.9.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.24</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.21</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.8.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.8.1</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId><version>3.0.5.RELEASE</version><exclusions><exclusion><groupId>org.elasticsearch.plugin</groupId><artifactId>transport-netty4-client</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.4.RELEASE</version></dependency></dependencies></project>
2)创建 applicationContext.xml 配置文件,引入 elasticsearch 命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/data/elasticsearchhttp://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd"></beans>
3)编写实体 Article
package com.domain;public class Article {private Integer id;private String title;private String content;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";}}
4)编写 Dao
package com.dao;import com.domain.Article;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {}
5)编写 Service
package com.service;import com.domain.Article;public interface ArticleService {public void save(Article article);}
package com.service.impl;import com.dao.ArticleRepository;
import com.domain.Article;
import com.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class ArticleServiceImpl implements ArticleService {@Autowiredprivate ArticleRepository articleRepository;public void save(Article article) {articleRepository.save(article);}}
6) 配置 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/data/elasticsearchhttp://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd"><!-- 扫描Dao包,自动创建实例 --><elasticsearch:repositories base-package="com.dao"/><!-- 扫描Service包,创建Service的实体 --><context:component-scan base-package="com.service"/><!-- 配置elasticSearch的连接 --><!-- 配置elasticSearch的连接 --><elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" cluster-name="my-elasticsearch"/><!-- ElasticSearch模版对象 --><bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate"><constructor-arg name="client" ref="client"></constructor-arg></bean>
</beans>
7)配置实体
基于 spring data elasticsearch 注解配置索引、映射和实体的关系
package com.domain;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.FieldType;//@Document 文档对象 (索引信息、文档类型 )
@Document(indexName="blog3",type="article")
public class Article {//@Id 文档主键 唯一标识@Id//@Field 每个文档的字段配置(类型、是否分词、是否存储、分词器 )@Field(store=true, index = false,type = FieldType.Integer)private Integer id;@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)private String title;@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)private String content;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";}}
其中,注解解释如下:
@Document(indexName="blob3",type="article"):indexName:索引的名称(必填项)type:索引的类型
@Id:主键的唯一标识
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)index:是否设置分词analyzer:存储时使用的分词器searchAnalyze:搜索时使用的分词器store:是否存储type: 数据类型
8)创建测试类 SpringDataESTest
package com.test;import com.domain.Article;
import com.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {@Autowiredprivate ArticleService articleService;@Autowiredprivate TransportClient client;@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;/**创建索引和映射*/@Testpublic void createIndex(){elasticsearchTemplate.createIndex(Article.class);elasticsearchTemplate.putMapping(Article.class);}/**测试保存文档*/@Testpublic void saveArticle(){Article article = new Article();article.setId(100);article.setTitle("测试SpringData ElasticSearch");article.setContent("Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 \n" +" Spring Data为Elasticsearch Elasticsearch项目提供集成搜索引擎");articleService.save(article);}}
public interface ArticleService {//保存public void save(Article article);//删除public void delete(Article article);//查询全部public Iterable<Article> findAll();//分页查询public Page<Article> findAll(Pageable pageable);}
import com.dao.ArticleRepository;
import com.domain.Article;
import com.service.ArticleService;
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 {@Autowiredprivate ArticleRepository articleRepository;public void save(Article article) {articleRepository.save(article);}public void delete(Article article) {articleRepository.delete(article);}public Iterable<Article> findAll() {Iterable<Article> iter = articleRepository.findAll();return iter;}public Page<Article> findAll(Pageable pageable) {return articleRepository.findAll(pageable);}
}
import com.domain.Article;
import com.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
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.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {@Autowiredprivate ArticleService articleService;@Autowiredprivate TransportClient client;@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;/**创建索引和映射*/@Testpublic void createIndex(){elasticsearchTemplate.createIndex(Article.class);elasticsearchTemplate.putMapping(Article.class);}/**测试保存文档*/@Testpublic void saveArticle(){Article article = new Article();article.setId(100);article.setTitle("测试SpringData ElasticSearch");article.setContent("Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 \n" +" Spring Data为Elasticsearch Elasticsearch项目提供集成搜索引擎");articleService.save(article);}/**测试保存*/@Testpublic void save(){Article article = new Article();article.setId(1001);article.setTitle("elasticSearch 3.0版本发布");article.setContent("ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口");articleService.save(article);}/**测试更新*/@Testpublic void update(){Article article = new Article();article.setId(1001);article.setTitle("elasticSearch 3.0版本发布...更新");article.setContent("ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口");articleService.save(article);}/**测试删除*/@Testpublic void delete(){Article article = new Article();article.setId(1001);articleService.delete(article);}/**批量插入*/@Testpublic void save100(){for(int i=1;i<=100;i++){Article article = new Article();article.setId(i);article.setTitle(i+"elasticSearch 3.0版本发布..,更新");article.setContent(i+"ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口");articleService.save(article);}}/**分页查询*/@Testpublic void findAllPage(){Pageable pageable = PageRequest.of(1,10);Page<Article> page = articleService.findAll(pageable);for(Article article:page.getContent()){System.out.println(article);}}
}
SpringBoot
1)添加 maven 依赖
<!--spring boot 整合 elasticsearch -->
<!--不用填写具体版本,spring boot 会自动找与之适配的 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2)配置 application.properties
旧版本
server.port=8091spring.elasticsearch.rest.uris=http://127.0.0.1:9200
spring.elasticsearch.rest.username=elastic
spring.elasticsearch.rest.password=1234567
新版本(去掉了 rest)
server.port=8091spring.elasticsearch.uris=http://127.0.0.1:9200
spring.elasticsearch.username=elastic
spring.elasticsearch.password=1234567
3)测试实体类
创建一个员工的实体类
关键注解 @Document、@Id、@Field
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;import java.math.BigDecimal;
import java.util.Date;/*** 员工实体类* @Document:作用在类上,标记实体类为文档对象。 indexName(索引名称,相当于数据库的表名称)* @Id:作用在成员变量上,标记一个字段作为id主键。 在Elasticsearch中,文档ID是唯一的,用于标识文档。* @Field:定义Java对象属性与Elasticsearch文档字段之间的映射关系。* @author*/
@Document(indexName = "employee_info")
public class EmployeeInfo {@Idprivate Long id;/*** 工号*/@Field(name = "job_no")private String jobNo;/*** 姓名*/@Field(name = "name")private String name;/*** 英文名*/@Field(name = "english_name")private String englishName;/*** 工作岗位*/private String job;/*** 性别*/private Integer sex;/*** 年龄*/private Integer age;/*** 薪资*/private BigDecimal salary;/*** 入职时间*/@Field(name = "job_day", format = DateFormat.date_time)private Date jobDay;/*** 备注*/private String remark;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getJobNo() {return jobNo;}public void setJobNo(String jobNo) {this.jobNo = jobNo;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEnglishName() {return englishName;}public void setEnglishName(String englishName) {this.englishName = englishName;}public String getJob() {return job;}public void setJob(String job) {this.job = job;}public Integer getSex() {return sex;}public void setSex(Integer sex) {this.sex = sex;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public BigDecimal getSalary() {return salary;}public void setSalary(BigDecimal salary) {this.salary = salary;}public Date getJobDay() {return jobDay;}public void setJobDay(Date jobDay) {this.jobDay = jobDay;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public EmployeeInfo() {}public EmployeeInfo(Long id, String jobNo, String name, String englishName, String job, Integer sex, Integer age, BigDecimal salary, Date jobDay, String remark) {this.id = id;this.jobNo = jobNo;this.name = name;this.englishName = englishName;this.job = job;this.sex = sex;this.age = age;this.salary = salary;this.jobDay = jobDay;this.remark = remark;}@Overridepublic String toString() {return "EmployeeInfo{" +"id=" + id +", jobNo='" + jobNo + '\'' +", name='" + name + '\'' +", englishName='" + englishName + '\'' +", job='" + job + '\'' +", sex=" + sex +", age=" + age +", salary=" + salary +", jobDay=" + jobDay +", remark='" + remark + '\'' +'}';}
}
方式一:继承 ElasticsearchRepository(适合简单查询)
ElasticsearchRepository 提供了一个高级的抽象,使得你可以在不编写任何实现代码的情况下,直接使用预定义的 CRUD 方法和查询方法。
业务层接口继承 ElasticsearchRepository 类
泛型的参数分别是实体类型和主键类型
例如:
public interface EmployeeInfoRepository extends ElasticsearchRepository<EmployeeInfo, Long> {
}
然后就可以直接使用了
添加单个文档
import com.example.springbootfull.elasticsearch.bean.EmployeeInfo;
import com.example.springbootfull.elasticsearch.service.EmployeeInfoRepository;
import com.example.springbootfull.elasticsearch.service.EmployeeInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;@RestController
@RequestMapping("/employeeInfo")
public class EmployeeElasticController {@Autowiredprivate EmployeeInfoRepository elasticRepository;@RequestMapping("/save")public String save() throws Exception {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");EmployeeInfo employeeInfo = new EmployeeInfo(6001L, "2001", "张三", "zhangsan", "Java", 1, 19, new BigDecimal("12500.01"), simpleDateFormat.parse("2019-09-10"), "备注");elasticRepository.save(employeeInfo);return "success";}}
想自定义自己的 Repository 接口
就要遵守 自定义方法命名规范
【自定义方法命名约定】:
Keyword | Sample | Elasticsearch Query string |
---|---|---|
And |
findBy NameAnd Price |
{"bool”[{"field” :{"name" :"?"}},{"field":{"price" :"?"}} ]}}:{must”::{"should" :[{"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or |
findBy NameOr Price |
{"bool”:{"must": {"field" : {"name" : "?"}}}} |
Is |
findByName |
{"bool”:{"must": {"field" : {"name" : "?"}}}} |
Not |
findBy NameNot |
{"bool”:{"must_not": {"field" : {"name" : "?"}}}} |
Between |
findBy PriceBetween |
{"bool":{"must": {"range" : {"price" : {"from" : ?,"to" : ?,"include_ lower":true,"include_upper" :true}}}}} |
LessThanEqual | findByPriceLessThan | {"bool": {"must":{"range" : {"price": {"from" : null,"to”: ?,"include_lower":true, "include_upper" : true}}}}} |
GreaterThanEqual | findByPriceGreaterThan | {"bool":{"must":{"range” :{ price" : {"from": ?,"to”:null,"include_ lower:"true, "include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool":{"must":{"range” :{ price" : {"from": null,"to":?,"include_lower": true, "include_upper" : true}}}}} |
After | findByPriceAfter | {"bool":{"must":{"range” :{ price” :{"from” :?."to”: null."include_ lower”:true,"include_upper":true}}}}} |
Like | findByNameLike | {"bool":{"must”:{"field” :{"name":{"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool":{"must” :{"field” :{"name” :{"query" :"?*","analyze_wildcard" : true}}}}} |
Endingwith | findByNameEndingWith | {"bool":{"must” :{"field” :{"name” :{"query" :"*?","analyze_wildcard" : true}}}}} |
Contains/Containing | findByNameContaining | {"bool”:{"must":i"field” :{"name":{ query" :"?”,"analyze wildcard” : true}}}}} |
In | findByNameIn(Collection |
{"boo1":{"must”:{"bool” :{"should" :[{"field" : {"name" :"?"}}, {"field” : {"name"?"}}]}}}} |
NotIn | findByNameNotIn(Collecti on |
{"bool": {"must not": {"bool": {"should": { field": {"name": "?"}}}}}} |
Near | findBvStoreNear | Not Supported Yet ! |
True | findBvAvailableTrue | {"bool":{"must":{"field":{ "available":true}}}} |
False | findBvAvailableFalse | {"bool":{"must":{"field":{ "available":false}}}} |
OrderBy |
findByAvailableTrueOrderByNameDesc |
{"sort" : [{ "name":{"order" :"desc"} }],"bool":{"must" : {"field" : {"available":true}}}} |
例如:我们来按照年龄区间查询,定义这样的一个方法findByAgeBetwee:
/*** 需要继承 ElasticsearchRepository 接口* 由于 Item 实体类中 id 为 Long 类型*/
public interface EmployeeInfoRepository extends ElasticsearchRepository<EmployeeInfo, Long>/*** 方法名必须遵守 SpringData 的规范* 年龄区间查询*/List<EmployeeInfo> findByAgeBetween(int age1, int age2);
}
然后,再通过 saveAll 新增多些数据,再进行自定义的方法进行查询
import com.example.springbootfull.elasticsearch.bean.EmployeeInfo;
import com.example.springbootfull.elasticsearch.service.EmployeeInfoRepository;
import com.example.springbootfull.elasticsearch.service.EmployeeInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;@RestController
@RequestMapping("/employeeInfo")
public class EmployeeElasticController {@Autowiredprivate EmployeeInfoRepository elasticRepository;@RequestMapping("/saveAll")public String saveAll() throws Exception {List<EmployeeInfo> list = new ArrayList<>();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");list.add(new EmployeeInfo(1001L, "2001", "张三", "zhangsan", "Java", 1, 19, new BigDecimal("12500.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1002L, "2002", "李四", "lisi", "PHP", 1, 18, new BigDecimal("11600.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1003L, "2003", "王五", "wangwu", "C++", 1, 20, new BigDecimal("9900.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1004L, "2004", "赵六", "zhaoliu", "Java Leader", 1, 20, new BigDecimal("20000.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1005L, "2005", "小五", "xiaowu", "H5", 1, 17, new BigDecimal("10600.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1006L, "2006", "小六", "xaioliu", "web", 1, 20, new BigDecimal("12600.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1007L, "2007", "小七", "xiaoqi", "app", 1, 22, new BigDecimal("20000.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1008L, "2008", "小八", "xaioba", "Java", 1, 21, new BigDecimal("11000.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1009L, "2009", "小九", "xiaojiu", "Java", 1, 20, new BigDecimal("14000.01"), simpleDateFormat.parse("2019-09-10"), "备注"));list.add(new EmployeeInfo(1010L, "2010", "大十", "dashi", "Java", 1, 20, new BigDecimal("13000.01"), simpleDateFormat.parse("2019-09-10"), "备注"));elasticRepository.saveAll(list);return "success -> " + list.size();}@RequestMapping("/findByAgeBetween")public String findByAgeBetween(){elasticRepository.findByAgeBetween(10,20);return "success";}}
方式二:使用 ElasticsearchRestTemplate(更适合用于复杂查询)
与 ElasticsearchRepository 相比,ElasticsearchRestTemplate 更适合用于复杂查询 。
比如 多个条件组合、范围查询、模糊查询、聚合查询等复杂场景
还支持分页、排序、过滤等高级功能
添加单个文档
@RestController
@RequestMapping("/employeeInfo")
public class EmployeeElasticController {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@RequestMapping("/template/save")public String templateSave() throws Exception {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");EmployeeInfo employeeInfo = new EmployeeInfo(8888L, "2001", "张八", "zhangsan", "Java", 1, 19, new BigDecimal("12500.01"), simpleDateFormat.parse("2019-09-10"), "备注");elasticsearchRestTemplate.save(employeeInfo);return "success";}
}
简单查询-通过 id
@RestController
@RequestMapping("/employeeInfo")
public class EmployeeElasticController {@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@RequestMapping("/getEmployeeInfo")public EmployeeInfo getEmployeeInfo() {return elasticsearchRestTemplate.get("6001", EmployeeInfo.class);}
}
常用查询命名规则
关键字 | 命名规则 | 解释 | 示例 |
---|---|---|---|
and | findByField1AndField2 | 根据Field1和Field2获得数据 | findByTitleAndContent |
or | findByField1OrField2 | 根据Field1或Field2获得数据 | findByTitleOrContent |
is | findByField | 根据Field获得数据 | findByTitle |
not | findByFieldNot | 根据Field获得补集数据 | findByTitleNot |
between | findByFieldBetween | 获得指定范围的数据 | findByPriceBetween |
lessThanEqual | findByFieldLessThan | 获得小于等于指定值的数据 | findByPriceLessThan |
查询方法测试
1)dao 层实现
package com.dao;import com.domain.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {//根据标题查询List<Article> findByTitle(String condition);//根据标题查询(含分页)Page<Article> findByTitle(String condition, Pageable pageable);
}
2)service 层实现
public interface ArticleService {//根据标题查询List<Article> findByTitle(String condition);//根据标题查询(含分页)Page<Article> findByTitle(String condition, Pageable pageable);
}
package com.service.impl;import com.dao.ArticleRepository;
import com.domain.Article;
import com.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class ArticleServiceImpl implements ArticleService {@Autowiredprivate ArticleRepository articleRepository;public List<Article> findByTitle(String condition) {return articleRepository.findByTitle(condition);}public Page<Article> findByTitle(String condition, Pageable pageable) {return articleRepository.findByTitle(condition,pageable);}}
3)测试代码
package com.test;import com.domain.Article;
import com.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
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.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {@Autowiredprivate ArticleService articleService;@Autowiredprivate TransportClient client;@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;/**条件查询*/@Testpublic void findByTitle(){String condition = "版本";List<Article> articleList = articleService.findByTitle(condition);for(Article article:articleList){System.out.println(article);}}/**条件分页查询*/@Testpublic void findByTitlePage(){String condition = "版本";Pageable pageable = PageRequest.of(2,10);Page<Article> page = articleService.findByTitle(condition,pageable);for(Article article:page.getContent()){System.out.println(article);}}}
使用 Elasticsearch 的原生查询对象进行查询。
@Test
public void findByNativeQuery() {//创建一个SearchQuery对象SearchQuery searchQuery = new NativeSearchQueryBuilder()//设置查询条件,此处可以使用QueryBuilders创建多种查询.withQuery(QueryBuilders.queryStringQuery("备份节点上没有数据").defaultField("title"))//还可以设置分页信息.withPageable(PageRequest.of(1, 5))//创建SearchQuery对象.build();//使用模板对象执行查询elasticsearchTemplate.queryForList(searchQuery, Article.class).forEach(a-> System.out.println(a));
}