搭建ES项目、使用java代码。可选的客户端有RestHighLevelClient、Spring Data Elasticsearch和Jest,本章将用一个搜索需求分别进行介绍。
Kibana是ELK家族中一个开源、免费的可视化数据搜索和分析平台。借助Kibana,用户不需要编码就可以将ES中分析的结果进行可视化呈现,如以常用的饼图、柱状图和时序图等方式呈现。除了可视化数据分析功能,Kibana还提供了Dev Tools,它是一款可以与ES进行交互式请求的工具,可以借助它进行DSL调试。限于篇幅,本节只介绍Kibana搭配单机版ES的配置方法
注意:最好保持和es版本一致。
下载地址:https://www.elastic.co/cn/downloads/kibana 版本直接下载:https://artifacts.elastic.co/downloads/kibana/kibana-7.10.2-windows-x86_64.zip
ES 和客户端的通信是根据Http来通信的。用户可以通过任意语言来进行通信。例如:java、Python等。java语言已经支持了很多的API只要拿来使用即可。
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.7-SNAPSHOTversion>
<relativePath/>
parent>
<groupId>com.xiaobaigroupId>
<artifactId>esartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>esname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.elasticsearch.clientgroupId>
<artifactId>elasticsearch-rest-high-level-clientartifactId>
<version>7.10.2version>
dependency>
<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>7.10.2version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
elasticsearch:
rest:
hosts: 127.0.0.1:9200
package com.example.xiaobai.es.resthightlevel;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.Objects;
@Configuration
public class EsClient {
@Value("${elasticsearch.rest.hosts:}") //读取ES主机+端口配置
private String hosts;
@Bean(value = "restHighLevelClient")
public RestHighLevelClient initSimpleClient() {
//根据配置文件配置HttpHost数组
HttpHost[] httpHosts = Arrays.stream(hosts.split(",")).map(
host -> {
//分隔ES服务器的IP和端口
String[] hostParts = host.split(":");
String hostName = hostParts[0];
int port = Integer.parseInt(hostParts[1]);
return new HttpHost(hostName, port, HttpHost.DEFAULT_SCHEME_NAME);
}).filter(Objects::nonNull).toArray(HttpHost[]::new);
//构建客户端
return new RestHighLevelClient(RestClient.builder(httpHosts));
}
}
@Bean(value = "restHighLevelClient")
public RestHighLevelClient initSimpleClient1() {
//根据配置文件配置HttpHost数组
HttpHost[] httpHosts = Arrays.stream(hosts.split(",")).map(
host -> {
//分隔ES服务器的IP和端口
String[] hostParts = host.split(":");
String hostName = hostParts[0];
int port = Integer.parseInt(hostParts[1]);
return new HttpHost(hostName, port, HttpHost.DEFAULT_SCHEME_NAME);
}).filter(Objects::nonNull).toArray(HttpHost[]::new);
// 生成凭证
final BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider();
basicCredentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(esUser,esPassword));
//构建客户端
return new RestHighLevelClient(RestClient.builder(httpHosts).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
return httpAsyncClientBuilder.setDefaultCredentialsProvider(basicCredentialsProvider);
}
}));
}
package com.xiaobai.es.pojo;
import lombok.Data;
@Data
public class Hotel {
/**
* 对应文档id
*/
private String id;
/**
* 索引名称
*/
private String index;
/**
* 分数
*/
private Float score;
/**
* 酒店 名称
*/
private String title;
/**
* 酒店城市
*/
private String city;
/**
* 酒店价格
*/
private Double price;
}
package com.xiaobai.es.service;
import com.xiaobai.es.pojo.Hotel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class EsService {
@Resource
private RestHighLevelClient restHighLevelClient;
private final static String INDEX_NAME = "hoteld";
public List<Hotel> getHotelFromTitle(String keyword){
// 客户端请求 创建请求对象 传入索引名称
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
// 构建查询条件对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 书写查询语句
searchSourceBuilder.query(QueryBuilders.matchQuery("title",keyword));
// 把查询语句设置给请求对象
searchRequest.source(searchSourceBuilder);
List<Hotel> hotels = new ArrayList<>();
// 查询
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
RestStatus status = searchResponse.status();
if (status != RestStatus.OK){
return hotels;
}
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
Hotel hotel = new Hotel();
hotel.setId(hit.getId());
hotel.setIndex(hit.getIndex());
hotel.setScore(hit.getScore());
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
hotel.setTitle((String) sourceAsMap.get("title"));
hotel.setCity((String) sourceAsMap.get("city"));
hotel.setPrice((Double) sourceAsMap.get("price"));
hotels.add(hotel);
}
} catch (IOException e) {
e.printStackTrace();
}
return hotels;
}
}
spring-data-elasticsearch是和springBoot中的一套组件。可以和es服务保持长链接,不需要每次查询的时候需要建立网络链接了。并且可以通过Repository接口自动实现,可以通过方法名的语义实现查询功能。而且查询到数据后可以直接封装到自定义pojo中。方便后续对数据的二次加工。
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.8version>
<relativePath/>
parent>
<groupId>com.sping.datagroupId>
<artifactId>springdataartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springdataname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>11java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
spring:
elasticsearch:
rest:
uris: http://127.0.0.1:9200
username: elastic
password: password
如果想要配置多个节点只需要uris 配置多个ip即可。中间用逗号分割。
@Data
@Document(indexName = "hoteld")
public class Hotel1 {
@Id
private String id;
private String title;
private String city;
private Double price;
}
@Id 代表是主键id 级文档id
/**
* @author liruiqing
*/
public interface EsRepository extends CrudRepository<Hotel1,String> {
/**
* 根据 title 查询符合的酒店
* @param title
* @return
*/
List<Hotel1> findByTitleLike(String title);
}
以方法名语义的方式实现查询数据。
需要继承CrudRepository
@Service
public class EsService {
@Autowired
private EsRepository esRepository;
public List<Hotel1> findByTitleLike(String keyword){
List<Hotel1> byTitleLike = esRepository.findByTitleLike(keyword);
return byTitleLike;
}
}
@RestController
public class TestController {
@Autowired
private EsService esService;
@RequestMapping("/test")
public String getHotelStr(){
List<Hotel1> hotels = esService.findByTitleLike("再来");
if (hotels.isEmpty()){
return "no data";
}
return hotels.toString();
}
}
Jest是为springBoot项目是低版本时做兼容时用到的,如果SpringBoot的版本过高的话application.yml中配置信息已经不生效了,被移除了。下面的版本是可以使用的。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<java.version>11java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>io.searchboxgroupId>
<artifactId>jestartifactId>
<version>6.3.1version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.elasticsearchgroupId>
<artifactId>elasticsearchartifactId>
<version>7.10.2version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>co.elastic.clientsgroupId>
<artifactId>elasticsearch-javaartifactId>
<version>7.17.8version>
<scope>compilescope>
dependency>
dependencies>
spring:
elasticsearch:
jest:
uris: http://127.0.0.1:9200
username: elastic
password: password
server:
port: 8082
@Data
public class Hotel {
@JestId // 文档id
private String id;
private String title;
private String city;
private Double price;
}
@Service
public class EsService {
@Resource
private JestClient jestClient;
public List<Hotel> findByTitleLike(String keyword){
// 创建sql语句对象 本次为查询语句
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", keyword);
// 设置查询builder对象 并把查询对象设置进去
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(matchQuery);
// 调用search.Builder把查询的builder对象字符串给设置进去 addIndex是索引名称
Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex("hoteld").build();
try {
// 使用jestClient.execute()方法获取searchResult数据对象 并把返回的数据集通过getSourceAsObjectList转换为集合
SearchResult searchResult = jestClient.execute(search);
if (searchResult.isSucceeded()){
List<Hotel> sourceAsObjectList = searchResult.getSourceAsObjectList(Hotel.class);
return sourceAsObjectList;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
@RestController
public class TestController {
@Autowired
private EsService esService;
@RequestMapping("/test")
public String findByTitleLike(){
List<Hotel> hotels = esService.findByTitleLike("再来");
if (hotels == null || hotels.isEmpty()){
return "no data";
}
return hotels.toString();
}
}