SpringBoot集成ElasticSearch
SpringBoot2.0自带集成ElasticSearch最高只支持5.6.10,所以高于5.6.10需要自己导入依赖,此说法来自网上,具体需要验证
pom.xml:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<hadoop.version>2.7.4</hadoop.version>
<scala.version>2.11</scala.version>
<spark.version>2.1.0</spark.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<elasticSearch.version>6.7.1</elasticSearch.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--elasticsearch-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticSearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticSearch.version}</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticSearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>${elasticSearch.version}</version>
</dependency>
<!--spark-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.version}</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_${scala.version}</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_${scala.version}</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_${scala.version}</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
</dependencies>
org.elasticsearch.client--transport 依赖添加之后,会依赖一系列的插件,客户端等,虽然在springboot2.0中依旧依赖 org.elasticsearch-elasticsearch-6.7.1,但是在依赖列表中,其添加的依赖依然是elasticSearch5.6.10的依赖,所以必须排除这个依赖,手动添加org.elasticsearch-elasticsearch6.7.1的依赖,目前只有这种解决方法,否则导致版本不一致冲突
还导入了一个 elasticsearch-rest-high-level-client的jar,为了使用其他API:https://www.cnblogs.com/ginb/p/8716485.html
目前我只是用了一个本地节点,ElasticSearchConfig:
package com.cn.ypp.elasticsearch;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
@Configuration
public class ElasticSearchConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${elasticsearch.ip}")
private String ip;
@Value("${elasticsearch.port}")
private String port;
@Value("${elasticsearch.clusterName}")
private String clusterName;
@Bean
public TransportClient getTransportClient() {
logger.info("ElasticSearch初始化开始。。");
logger.info("要连接的节点的ip是{},端口是{},集群名为{}" , ip , port , clusterName);
TransportClient transportClient = null;
try {
Settings settings = Settings.builder()
//集群名称
.put("cluster.name",clusterName)
//目的是为了可以找到集群,嗅探机制开启
.put("client.transport.sniff",true)
.build();
transportClient = new PreBuiltTransportClient(settings);
TransportAddress es = new TransportAddress(InetAddress.getByName(ip),Integer.parseInt(port));
transportClient.addTransportAddress(es);
logger.info("ElasticSearch初始化完成。。");
}catch (Exception e){
e.printStackTrace();
logger.error("ElasticSearch初始化失败:" + e.getMessage(),e);
}
return transportClient;
}
}
如果是集群,像下面这样:
package com.cn.ypp.elasticsearch;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
@Configuration
public class ElasticSearchConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${elasticsearch.firstIp}")
private String firstIp;
@Value("${elasticsearch.secondIp}")
private String secondIp;
@Value("${elasticsearch.thirdIp}")
private String thirdIp;
@Value("${elasticsearch.firstPort}")
private String firstPort;
@Value("${elasticsearch.secondPort}")
private String secondPort;
@Value("${elasticsearch.thirdPort}")
private String thirdPort;
@Value("${elasticsearch.clusterName}")
private String clusterName;
@Bean
public TransportClient getTransportClient() {
logger.info("ElasticSearch初始化开始。。");
logger.info("要连接的节点1的ip是{},端口是{},集群名为{}" , firstIp , firstPort , clusterName);
logger.info("要连接的节点2的ip是{},端口是{},集群名为{}" , secondIp , secondPort , clusterName);
logger.info("要连接的节点3的ip是{},端口是{},集群名为{}" , thirdIp , thirdPort , clusterName);
TransportClient transportClient = null;
try {
Settings settings = Settings.builder()
//集群名称
.put("cluster.name",clusterName)
//目的是为了可以找到集群,嗅探机制开启
.put("client.transport.sniff",true)
.build();
transportClient = new PreBuiltTransportClient(settings);
TransportAddress firstAddress = new TransportAddress(InetAddress.getByName(firstIp),Integer.parseInt(firstPort));
TransportAddress secondAddress = new TransportAddress(InetAddress.getByName(secondIp),Integer.parseInt(secondPort));
TransportAddress thirdAddress = new TransportAddress(InetAddress.getByName(thirdIp),Integer.parseInt(thirdPort));
transportClient.addTransportAddress(firstAddress);
transportClient.addTransportAddress(secondAddress);
transportClient.addTransportAddress(thirdAddress);
logger.info("ElasticSearch初始化完成。。");
}catch (Exception e){
e.printStackTrace();
logger.error("ElasticSearch初始化失败:" + e.getMessage(),e);
}
return transportClient;
}
}
以上的都是网上的说法,所以引入了相关的jar和配置类
常用基本操作:
GET _cat/indices?v 查看健康值
GET /_cat/nodes?v 获取节点列表
GET _cat/indices?v 列出所有索引
目前是空的,没有创建过索引
使用java操作索引等:
Elasticsearch JAVA操作有三种客户端:
1、TransportClient
2、JestClient
3、RestClient
4、spring-boot-starter-data-elasticsearch(有待验证,据说最高只支持elasticsearch2.x版本)
先试一试spring-boot-starter-data-elasticsearch
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
application.yml:
server:
port: 8054
spark:
spark-home: .
app-name: sparkTest
master: local[4]
# ELASTICSEARCH (ElasticsearchProperties)
# Elasticsearch cluster name.
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: localhost:9300
repositories:
enabled: true
Book:
package com.cn.ypp.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "book", type = "_doc")
public class Book extends BaseEntity{
private String title;
private String author;
private String postDate;
public Book(){}
public Book(String id, String title, String author, String postDate){
setId(id);
this.title = title;
this.author=author;
this.postDate=postDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPostDate() {
return postDate;
}
public void setPostDate(String postDate) {
this.postDate = postDate;
}
@Override
public String toString() {
return "book{" +
"id='" + getId() + '\'' +
", title='" + title + '\'' +
", author='" + author + '\'' +
", postDate='" + postDate + '\'' +
'}';
}
}
BaseEntity:
package com.cn.ypp.entity;
import org.springframework.data.annotation.Id;
public class BaseEntity {
@Id
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
BookRepository:
package com.cn.ypp.elasticsearch.dao;
import com.cn.ypp.entity.Book;
import org.apache.commons.net.nntp.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 BookRepository extends ElasticsearchRepository<Book,String> {
Page<Book> findByAuthor(String author, Pageable pageable);
Page<Book> findByTitle(String title, Pageable pageable);
List<Book> findByTitle(String title);
}
BookService:
package com.cn.ypp.elasticsearch.service;
import com.cn.ypp.entity.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import java.util.List;
import java.util.Optional;
public interface BookService {
Optional<Book> findById(String id);
Book save(Book blog);
void delete(Book blog);
Optional<Book> findOne(String id);
List<Book> findAll();
Page<Book> findByAuthor(String author, PageRequest pageRequest);
Page<Book> findByTitle(String title, PageRequest pageRequest);
List<Book> findTitle(String titileKeyword);
Iterable<Book> saveAll(List<Book> books);
}
BookServiceImpl:
package com.cn.ypp.elasticsearch.service;
import com.cn.ypp.elasticsearch.dao.BookRepository;
import com.cn.ypp.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookRepository bookRepository;
@Override
public Optional<Book> findById(String id) {
//CrudRepository中的方法
return bookRepository.findById(id);
}
@Override
public Book save(Book blog) {
return bookRepository.save(blog);
}
@Override
public void delete(Book blog) {
bookRepository.delete(blog);
}
@Override
public Optional<Book> findOne(String id) {
return bookRepository.findById(id);
}
@Override
public List<Book> findAll() {
return (List<Book>) bookRepository.findAll();
}
@Override
public Page<Book> findByAuthor(String author, PageRequest pageRequest) {
return bookRepository.findByAuthor(author,pageRequest);
}
@Override
public Page<Book> findByTitle(String title, PageRequest pageRequest) {
return bookRepository.findByTitle(title,pageRequest);
}
@Override
public List<Book> findTitle(String titileKeyword) {
return bookRepository.findByTitle(titileKeyword);
}
@Override
public Iterable<Book> saveAll(List<Book> books) {
return bookRepository.saveAll(books);
}
}
EsController:
package com.cn.ypp.elasticsearch.controller;
import com.cn.ypp.elasticsearch.service.BookService;
import com.cn.ypp.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
@Controller
@RequestMapping("/es")
public class EsController {
@Autowired
private BookService bookService;
@RequestMapping("/book/{id}")
@ResponseBody
public Book getBookById(@PathVariable String id){
Optional<Book> opt =bookService.findById(id);
Book book=opt.get();
System.out.println(book);
return book;
}
@RequestMapping("/save")
@ResponseBody
public void Save(){
Book book1=new Book("1","ES入门教程","ypp","2018-10-01");
Book book2=new Book("2","从ES入门教程到放弃java","ypp","2018-10-01");
Book book3=new Book("3","mysql从入门到放弃","ypp","2018-10-01");
Book book4=new Book("4","redis从入门到放弃","ypp","2018-10-01");
Book book5=new Book("5","spark从入门到放弃","ypp","2018-10-01");
Book book6=new Book("6","hbase从入门到放弃","ypp","2018-10-01");
Book book7=new Book("7","zookeeper从入门到放弃","ypp","2018-10-01");
Book book8=new Book("8","mq从入门到放弃","ypp","2018-10-01");
Book book9=new Book("9","spring cloud从入门到放弃","ypp","2018-10-01");
List<Book> books=new ArrayList<>();
books.add(book1);
books.add(book2);
books.add(book3);
books.add(book4);
books.add(book5);
books.add(book6);
books.add(book7);
books.add(book8);
books.add(book9);
bookService.saveAll(books);
}
@RequestMapping("/keyword")
@ResponseBody
public List<Book> keyword(@RequestParam("keyword")String keyword){
return bookService.findTitle(keyword);
}
}
发送请求:http://localhost:8054/es/save
查看elasticsearch:
事实证明是可以的。自己实践才是真理,其他3种方式有时间继续干
有一点说明的是在BookRepository里面有一个方法findByTitle,本身ES顶部等接口都没有方法,也没有实现,是如何查询到的呢?这里不需要实现类,会自动创建实现类,具体如何实现不清楚,对ES来说是个新手,但大概能猜出应该是动态代理(如有错误,请纠错,十分感谢)
还有方法只要符合一定的规则,它就可以自动发现并为你实现,以name字段举例:
And findByNameAndPwd
Or findByNameOrSex
Is findById
Between findByIdBetween
Like findByNameLike
NotLike findByNameNotLike
OrderBy findByIdOrderByXDesc
Not findByNameNot
这也就能说明为什么findByTitle能查询到了,结果如下
我只查询的mysql,它自动实现了英文分词?
如果需要比较复杂的查询,就需要借助ElasticsearchTemplate来进行实现了
EsBookRepository:
package com.cn.ypp.elasticsearch.dao;
import com.cn.ypp.entity.Book;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import java.util.Date;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.*;
public class EsBookRepository {
@Autowired
private BookRepository bookRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
public List<Book> page() {
//查询关键字
String word = "ypp-mysql娃哈哈入门";
// 分页设置,id倒序
Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC, "id");
SearchQuery searchQuery;
//0.使用queryStringQuery完成单字符串查询queryStringQuery(word, "title")
//1.multiMatchQuery多个字段匹配 .operator(MatchQueryBuilder.Operator.AND)多项匹配使用and查询即完全匹配都存在才查出来
//searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery(word, "title", "content").operator(MatchQueryBuilder.Operator.AND)).withPageable(pageable).build();
//2.多条件查询:title和author必须包含word=“XXX”且postDate必须小于当前时间以id倒序分页结果
searchQuery = new NativeSearchQueryBuilder()
.withQuery(
new BoolQueryBuilder().must(multiMatchQuery(word, "title", "author").operator(Operator.AND))
.must(rangeQuery("postDate").lt(new Date())
)
)
.withPageable(pageable)
.build();
return elasticsearchTemplate.queryForList(searchQuery, Book.class);
}
}