目录
- ElasticSearch - 编程实现
- 1. ElasticSearch 编程操作
- 1.1 创建工程,导入坐标
- 1.2 创建索引 index
- 1.3 创建映射 mapping
- 1.4 建立文档 document
- 1.4.1 建立文档(通过XContentBuilder)
- 1.4.2 建立文档(使用Jackson转换实体)
- 1.5 查询文档操作
- 1.5.1 termQuery
- 1.5.2 QueryString
- 1.5.3 MatchQuery
- 1.5.4 重构查询方法
- 1.5.5 使用文章ID查询文档
- 1.5.6 查询文章分页操作
- 1.6 查询结果高亮操作
- 1.6.1 高亮显示
- 1.6.2 高亮显示的HTML分析
- 1.6.3 高亮代码实现
- 2. Spring Data ElasticSearch
- 2.1 简介
- 2.1.1 Spring Data
- 2.1.2 Spring Data ElasticSearch
- 2.2 入门案例
ElasticSearch版本:5.6.8
1. ElasticSearch 编程操作 1.1 创建工程,导入坐标
pom.xml
1.2 创建索引 indexorg.elasticsearch elasticsearch 5.6.8 org.elasticsearch.client transport 5.6.8 org.apache.logging.log4j log4j-to-slf4j 2.9.1 org.slf4j slf4j-api 1.7.24 org.slf4j slf4j-simple 1.7.21 log4j log4j 1.2.17 junit junit 4.12 test
代码
@Test
public void createIndex() throws Exception {
// 1. 配置
Settings settings = Settings.builder().put("cluster.name","murphy-application").build();
// 2. 客户端
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.2.180"),9300));
// 3. 创建索引 - 使用API
client.admin().indices().prepareCreate("index_hello").get();
// 4. 释放资源 - 关闭client
client.close();
}
运行结果
1.3 创建映射 mapping代码
@Test
public void setMappings() throws Exception {
// 1. 配置 - 创建Client连接对象
Settings settings = Settings.builder().put("cluster.name","murphy-application").build();
// 2. 客户端
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.2.180"),9300));
// 添加映射
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();
// 创建映射
client.admin().indices().preparePutMapping("index_hello").setType("article").setSource(builder).get();
// 4. 释放资源 - 关闭client
client.close();
}
运行结果
1.4 建立文档 document 1.4.1 建立文档(通过XContentBuilder)代码
@Test
public void testAdddocument() throws Exception {
// 创建一个client对象
// 创建一个文档对象
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("id",21)
.field("title","近日以来,北方的秋天悄然来临..")
.field("content","北方入秋速度明显加快,多地降温幅度最多可达10度")
.endObject();
// 把文档对象添加到索引库
client.prepareIndex()
// 设置索引名称
.setIndex("index_hello")
// 设置type
.setType("article")
// 设置文档的ID,如果不设置的话,自动生成一个ID
.setId("2")
// 设置文档信息
.setSource(builder)
// 执行操作
.get();
client.close();
}
运行结果
1.4.2 建立文档(使用Jackson转换实体)- 创建Article实体
public class Article {
private Integer id;
private String title;
private String content;
}
- 添加Jackson坐标依赖
com.fasterxml.jackson.core jackson-core 2.12.3 com.fasterxml.jackson.core jackson-databind 2.12.3 com.fasterxml.jackson.core jackson-annotations 2.12.3
- 代码实现
@Test
public void testAdddocument2() throws Exception {
// 创建一个Article对象
Article article = new Article();
// 设置对象的属性
article.setId(22);
article.setTitle("ElasticSearch是一个基于Lucene的搜索服务器");
article.setContent("它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。 Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。");
// 使用article对象转换成json格式的字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsondocument = objectMapper.writevalueAsString(article);
System.out.println(jsondocument);
// 使用client对象把文档写入索引库
client.prepareIndex("index_hello","article","3")
.setSource(jsondocument, XContentType.JSON)
.get();
// 关闭客户端
client.close();
}
- 运行结果
测试用例
1.5.1 termQuery
@Test
public void testQueryByTerm() throws Exception {
// 1. 构建QueryBuilder - 参数1:要搜索的字段 / 参数2:要搜索的关键词
QueryBuilder queryBuilder = QueryBuilders.termQuery("title","重磅");
// 2. 执行查询得到结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
// 3. 处理结果
SearchHits searchHits = searchResponse.getHits();
// 查询结果的总记录数
System.out.println("总行数:" + searchHits.getTotalHits());
// 查询结果列表
Iterator iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(searchHit.getSourceAsString());
// 取文档的属性
System.out.println("--- 文档属性 ---");
Map document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
// 关闭client
client.close();
}
1.5.2 QueryString
@Test
public void testQueryByTerm() throws Exception {
// 1. 构建QueryBuilder
QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("微信").defaultField("title");
// 2. 执行查询得到结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
// 3. 处理结果
SearchHits searchHits = searchResponse.getHits();
// 查询结果的总记录数
System.out.println("总行数:" + searchHits.getTotalHits());
// 查询结果列表
Iterator iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(searchHit.getSourceAsString());
// 取文档的属性
System.out.println("--- 文档属性 ---");
Map document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
// 关闭client
client.close();
}
1.5.3 MatchQuery
@Test
public void testQueryByMatch() throws Exception {
// 1. 构建QueryBuilder - 参数1:要搜索的字段 / 参数2:要搜索的关键词
QueryBuilder queryBuilder = QueryBuilders.matchQuery("title","微信");
// 2. 执行查询得到结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
// 3. 处理结果
SearchHits searchHits = searchResponse.getHits();
// 查询结果的总记录数
System.out.println("总行数:" + searchHits.getTotalHits());
// 查询结果列表
Iterator iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(searchHit.getSourceAsString());
// 取文档的属性
System.out.println("--- 文档属性 ---");
Map document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
// 关闭client
client.close();
}
1.5.4 重构查询方法
// 提取
private void search(QueryBuilder queryBuilder) {
// 1. 执行查询得到结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
// 2. 处理结果
SearchHits searchHits = searchResponse.getHits();
System.out.println("总行数:" + searchHits.getTotalHits());
Iterator iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(searchHit.getSourceAsString());
System.out.println("--- 文档属性 ---");
Map document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
// 关闭client
client.close();
}
1.5.5 使用文章ID查询文档
@Test
public void testQueryById() throws Exception {
// 1. 构建QueryBuilder - 可以查询多个ID
QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("4","5","6");
// 2. 执行查询得到结果
search(queryBuilder);
}
1.5.6 查询文章分页操作
@Test
public void testQueryByMatchAll() throws Exception {
// 1. 构建QueryBuilder
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
// 2. 执行查询得到结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
// 设置分页信息
.setFrom(0)
// 每页显示的行数
.setSize(5)
.get();
// 3. 处理结果
SearchHits searchHits = searchResponse.getHits();
System.out.println("总行数:" + searchHits.getTotalHits());
Iterator iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(searchHit.getSourceAsString());
System.out.println("--- 文档属性 ---");
Map document = searchHit.getSource();
System.out.println(document.get("id"));
System.out.println(document.get("title"));
System.out.println(document.get("content"));
}
// 关闭client
client.close();
}
1.6 查询结果高亮操作
1.6.1 高亮显示
在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。
1.6.2 高亮显示的HTML分析通过开发者工具查看高亮数据的html代码实现:
- ElasticSearch可以对查询出的内容中关键字部分进行标签和样式的设置,但是你需要告诉ElasticSearch使用什么标签对高亮关键字进行包裹。
@Test
public void testSearchHighlight() throws Exception {
// 创建一个client对象 - 查询对象
// QueryBuilder queryBuilder = QueryBuilders.matchQuery("title","北方");
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("北方","title","content");
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.field("content");
highlightBuilder.preTags("");
highlightBuilder.postTags(" iterator = searchHits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
// Source -> document的JSON输出
System.out.println(" -- 文档内容 -- ");
System.out.println(searchHit.getSourceAsString());
// 取title高亮显示的结果
System.out.println(" -- 高亮结果 -- ");
Map highlightFields = searchHit.getHighlightFields();
for (Map.Entry entry : highlightFields.entrySet()) {
System.out.println(entry.getKey() + ":t" + Arrays.toString(entry.getValue().getFragments()));
}
}
// 关闭client
client.close();
}
2. Spring Data ElasticSearch 2.1 简介 2.1.1 Spring Data
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法, 可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。
Spring Data的官网:http://projects.spring.io/spring-data/
Spring Data常用的功能模块如下:
2.1.2 Spring Data ElasticSearchSpring Data ElasticSearch基于spring data API简化elasticSearch操作,将原始操作elasticSearch的客户端API进行封装。Spring Data为Elasticsearch项目提供集成搜索引擎。Spring Data Elasticsearch POJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储库数据访问层。
官方网站:http://projects.spring.io/spring-data-elasticsearch/
2.2 入门案例查询用例
- 导入Spring Data ElasticSearch坐标
4.0.0 com.murphy SpringData-Demo 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 2.1.16.RELEASE 1.8 org.springframework.boot spring-boot-starter-data-elasticsearch org.springframework.boot spring-boot-starter-test org.springframework.boot spring-boot-maven-plugin
- 启动配置器文件
@SpringBootApplication
public class EsApplication {
public static void main(String[] args) {
SpringApplication.run(EsApplication.class, args);
}
}
spring:
data:
elasticsearch:
cluster-name: murphy-application
cluster-nodes: 192.168.2.170:9300
- 编写实体类
@document(indexName = "murphy_blog", type = "article")
public class Article {
@Id
@Field(type = FieldType.Long, store = true)
private Long id;
@Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
private String title;
@Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
private String content;
@Override
public String toString() {
return "Article{" +
"id=" + id +
", title='" + title + ''' +
", content='" + content + ''' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long 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;
}
}
- 编写Dao
- 方法命名规则查询的基本语法:findBy + 属性 + 关键词 + 连接符
public interface ArticleDao extends ElasticsearchRepository{ public List findByTitle(String title); public List findByTitleLike(String title); public List findByTitleOrContent(String title, String content); public List findByTitleOrContent(String title, String content, Pageable pageable); }
- 创建测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class EsApplicationTest {
@Autowired
private ArticleDao articleDao;
@Autowired
private ElasticsearchTemplate template;
@Test
public void createIndex() {
// 创建索引 + mapping
template.createIndex(Article.class);
// 配置mapping - template.putMapping(Article.class)
}
@Test
public void adddocument() throws Exception {
for (int i = 1; i <= 20; i++) {
// 创建一个 Article 对象
Article article = new Article();
article.setId(new Long(i));
article.setTitle("近日以来,北方的秋天悄然来临.." + i);
article.setContent("北方入秋速度明显加快,多地降温幅度最多可达10度" + i);
// 把文档写入索引库
articleDao.save(article);
}
}
@Test
public void deletedocumentById() throws Exception {
// 根据ID删除
articleDao.deleteById(3l);
// 全部删除 - articleDao.deleteAll();
}
@Test
public void findAll() {
articleDao.findAll().forEach(System.out :: println);
}
@Test
public void findById() {
System.out.println(articleDao.findById(1l));
}
@Test
public void findByTitle() {
articleDao.findByTitle("秋天").forEach(System.out :: println);
System.out.println("---");
// Like - 可以进行分词查询
articleDao.findByTitleLike("美丽秋天").forEach(System.out :: println);
}
@Test
public void findByTitleOrContent() {
articleDao.findByTitleOrContent("秋天","无此").forEach(System.out :: println);
}
@Test
public void findByTitlePage() {
Pageable pageable = PageRequest.of(1,5);
articleDao.findByTitleOrContent("秋天","北方", pageable).forEach(System.out :: println);
}
@Test
public void testNativeSearchQuery() throws Exception {
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery("北方").defaultField("title"))
.withPageable(PageRequest.of(1,5))
.build();
template.queryForList(query, Article.class).forEach(System.out :: println);
}
}



