前面使用了 SpringBoot 整合了 Solr: [增删改查] SpringBoot 整合 Solr 实现 CRUD、分页接口、高亮显示
眼下有一个比 Solr
还火热的 ElasticSearch
,主要是用于大数据、分布式系统中,顺便使用 SpringBoot
来整合
Elasticsearch是一个基于Lucene的搜索服务器。
它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
使用的方式主要两种:
① 一种是经过 SpringData
封装过的,直接在 dao 接口继承 ElasticsearchRepository 即可
② 一种是经过 Spring
封装过的,直接在 Service/Controller 中引入该 bean 即可
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
2018.7.14更新,代码已经放到 github 上了:https://github.com/larger5/SpringBoot_ElasticSearch_base.git
package com.cun.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
/**
* 加上了@Document注解之后,默认情况下这个实体中所有的属性都会被建立索引、并且分词
* @author linhongcun
*
*/
//http://120.79.197.131:9200/product
@Document(indexName = "product", type = "book")
public class Book {
@Id
String id;
String name;
String message;
String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
package com.cun.dao;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import com.cun.entity.Book;
public interface BookDao extends ElasticsearchRepository<Book,String>{
}
package com.cun.controller;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.highlight.HighlightBuilder;
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.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.cun.dao.BookDao;
import com.cun.entity.Book;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@RestController
@RequestMapping("/book")
@EnableSwagger2
public class BookController {
@Autowired
private BookDao bookDao;
/**
* 1、查 id
* @param id
* @return
*/
@GetMapping("/get/{id}")
public Book getBookById(@PathVariable String id) {
return bookDao.findOne(id);
}
/**
* 2、查 ++:全文检索(根据整个实体的所有属性,可能结果为0个)
* @param q
* @return
*/
@GetMapping("/select/{q}")
public List<Book> testSearch(@PathVariable String q) {
QueryStringQueryBuilder builder = new QueryStringQueryBuilder(q);
Iterable<Book> searchResult = bookDao.search(builder);
Iterator<Book> iterator = searchResult.iterator();
List<Book> list = new ArrayList<Book>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
/**
* 3、查 +++:分页、分数、分域(结果一个也不少)
* @param page
* @param size
* @param q
* @return
* @return
*/
@GetMapping("/{page}/{size}/{q}")
public List<Book> searchCity(@PathVariable Integer page, @PathVariable Integer size, @PathVariable String q) {
// 分页参数
Pageable pageable = new PageRequest(page, size);
// 分数,并自动按分排序
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
.add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("name", q)),
ScoreFunctionBuilders.weightFactorFunction(1000)) // 权重:name 1000分
.add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("message", q)),
ScoreFunctionBuilders.weightFactorFunction(100)); // 权重:message 100分
// 分数、分页
SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable)
.withQuery(functionScoreQueryBuilder).build();
Page<Book> searchPageResults = bookDao.search(searchQuery);
return searchPageResults.getContent();
}
/**
* 4、增
* @param book
* @return
*/
@PostMapping("/insert")
public Book insertBook(Book book) {
bookDao.save(book);
return book;
}
/**
* 5、删 id
* @param id
* @return
*/
@DeleteMapping("/delete/{id}")
public Book insertBook(@PathVariable String id) {
Book book = bookDao.findOne(id);
bookDao.delete(id);
return book;
}
/**
* 6、改
* @param book
* @return
*/
@PutMapping("/update")
public Book updateBook(Book book) {
bookDao.save(book);
return book;
}
}
package com.cun.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 简单使用 elasticsearchTemplate
* @author linhongcun
*
*/
@RestController
@RequestMapping("/template")
public class BookControllerTemplate {
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
/**
* 查询所有
* @throws Exception
*/
@GetMapping("/all")
public List<Map<String, Object>> searchAll() throws Exception {
//这一步是最关键的
Client client = elasticsearchTemplate.getClient();
// @Document(indexName = "product", type = "book")
SearchRequestBuilder srb = client.prepareSearch("product").setTypes("book");
SearchResponse sr = srb.setQuery(QueryBuilders.matchAllQuery()).execute().actionGet(); // 查询所有
SearchHits hits = sr.getHits();
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (SearchHit hit : hits) {
Map<String, Object> source = hit.getSource();
list.add(source);
System.out.println(hit.getSourceAsString());
}
return list;
}
}
server:
context-path: /
port: 80
spring:
data:
elasticsearch:
cluster-name: elasticsearch #默认即为 elasticsearch
cluster-nodes: 120.79.197.131:9300 #配置es节点信息,逗号分隔,如果没有指定,则启动ClientNode
org.springframework.boot
spring-boot-starter-data-elasticsearch
使用 Swagger 生成接口测试页面,所有接口均经过测试,完全没有问题!
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.7.0version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.6.1version>
dependency>
Ⅰ、应用
Github、StackOverFlow
等网站都是使用 ElasticSearch 作为搜索引擎的
Ⅱ、参考文章:
① springboot整合elasticsearch入门例子
②Spring Boot 整合Elasticsearch
③spring 操作elasticsearch
④ ElasticSearch搜索实例含高亮显示及搜索的特殊字符过滤
⑤ docker环境 快速使用elasticsearch-head插件
Ⅲ、其他知识须知
9300端口: ES节点之间通讯使用
9200端口: ES节点 和 外部 通讯使用