赞
踩
目录
10.4.1、SpringAMQP-FanoutExchange
10.4.2、SpringAMQP-DirectExhange、TopicExchange
11.1.1、初识elasticsearch-正向索引和倒排索引
11.3.6、DSL查询语法-Function Score Query
11.6.2、数据聚合-DSL实现Buckey聚合(桶聚合)
11.6.3、数据聚合-DSL实现Metrics聚合(嵌套聚合)
单体架构特点?
分布式架构特点?
1.微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同业务
2.微服务可以将业务暴露为接口,供其它微服务使用
3.不同微服务都应该有自己独立的数据库
在Eureka架构中,微服务角色有两类:
1.EurekaServer:服务端,注册中心
- 记录服务信息
- 心跳监控
2.EurekaClient:客户端
Provider:服务提供者,例如案例中的user-service
- 注册自己的信息到EurekaServer
- 每隔30秒向EurekaServer发送心跳
Consumer:服务消费者,例如案例中的order-service
- 根据服务名称从EurekaServer拉去服务列表
- 基于服务列表做负载均衡,选中一个微服务后发起远程调用
将配置交给Nacos管理步骤
Nacos配置更改后,微服务可以实现热更新,方式:
注意事项:
微服务会从nacos读取的配置文件:
优先级:
微服务默认读取的配置文件:
不同微服务共享的配置文件:
优先级:
Nacos集群搭建步骤:
1、方式一是配置文件,feign.client.config.xxx.loggerLever
2、方式二是java代码配置Logger.Lever这个Bean
1、日志级别尽量用Basic
2、使用HttpClient或OKHttp替代URLConnection
方式一(继承):给消费者的FeignClient和提供者的controller定义同一的父接口为标准
弊端:
方式二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
实现最佳实践方式二的步骤如下:
重启之后出现的问题,因为新建的模块在不同包下,所以在order-service项目启动时,无法引入
不同包的FeignClient的导入有两种方式:
PredicateFactory的作用是什么?
Path = /user/**是什么含义?
过滤器的作用是什么?
defaultFilters的作用是什么?
全局过滤器的作用是什么?
实现全局过滤器的步骤?
路由过滤器、defaultFilter、全局过滤器的执行顺序?
Docker是一个快速交付应用、运行应用的技术:
镜像:
容器:
Docker结构:
DockerHub:
docker run 命令的常见参数有哪些?
查看容器日志的命令:
查看容器状态
删除容器
进入容器
数据卷的作用:
数据卷操作:
数据卷挂载方式:
数据卷管理:
1、docker run 的命令中通过 -v 参数挂载文件或目录到容器中
2、数据卷挂载与目录直接挂载的
镜像是分层结构,每一层称为一个Layer
DockerCompose有什么作用?
同步调用的优点:
同步调用的问题:
异步通讯的优点:
异步通讯的缺点:
RabbitMQ的几个概念:
基本消息队列的消息发送流程:
- package cn.itcast.mq.helloworld;
-
- import com.rabbitmq.client.Channel;
- import com.rabbitmq.client.Connection;
- import com.rabbitmq.client.ConnectionFactory;
- import org.junit.Test;
-
- import java.io.IOException;
- import java.util.concurrent.TimeoutException;
-
- public class PublisherTest {
- @Test
- public void testSendMessage() throws IOException, TimeoutException {
- // 1.建立连接
- ConnectionFactory factory = new ConnectionFactory();
- // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
- factory.setHost("192.168.16.3");
- factory.setPort(5672);
- factory.setVirtualHost("/");
- factory.setUsername("liufang");
- factory.setPassword("123456");
- // 1.2.建立连接
- Connection connection = factory.newConnection();
-
- // 2.创建通道Channel
- Channel channel = connection.createChannel();
-
- // 3.创建队列
- String queueName = "simple.queue";
- channel.queueDeclare(queueName, false, false, false, null);
-
- // 4.发送消息
- String message = "hello, rabbitmq!";
- channel.basicPublish("", queueName, null, message.getBytes());
- System.out.println("发送消息成功:【" + message + "】");
-
- // 5.关闭通道和连接
- channel.close();
- connection.close();
-
- }
- }
基本消息队列的消息接收流程:
- package cn.itcast.mq.helloworld;
-
- import com.rabbitmq.client.*;
-
- import java.io.IOException;
- import java.util.concurrent.TimeoutException;
-
- public class ConsumerTest {
-
- public static void main(String[] args) throws IOException, TimeoutException {
- // 1.建立连接
- ConnectionFactory factory = new ConnectionFactory();
- // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
- factory.setHost("192.168.16.3");
- factory.setPort(5672);
- factory.setVirtualHost("/");
- factory.setUsername("liufang");
- factory.setPassword("123456");
- // 1.2.建立连接
- Connection connection = factory.newConnection();
-
- // 2.创建通道Channel
- Channel channel = connection.createChannel();
-
- // 3.创建队列
- String queueName = "simple.queue";
- channel.queueDeclare(queueName, false, false, false, null);
-
- // 4.订阅消息
- channel.basicConsume(queueName, true, new DefaultConsumer(channel){
- @Override
- public void handleDelivery(String consumerTag, Envelope envelope,
- AMQP.BasicProperties properties, byte[] body) throws IOException {
- // 5.处理消息
- String message = new String(body);
- System.out.println("接收到消息:【" + message + "】");
- }
- });
- System.out.println("等待接收消息。。。。");
- }
- }
什么是AMQP?
SpringAMQP如何发送消息?
SpringAMQP如何接收消息?
注意:消息一旦消费就会从队列删除,RabbitMQ没有消息回溯功能
Work模型的使用:
交换机的作用是什么?
声明队列、交换机、绑定关系的Bean是什么?
描述下Direct交换机与Fanout交换机的差别?
基于@RabbitListener注解声明队列和交换机有哪些常见注解?
描述下Topic交换机与Direct交换机的差异?
SpringAMQP中消息的序列化和反序列化是怎么实现的?
RabbitMQ只支持字节,Spring却允许我们发Object对象,说明它会将我们的对象做序列化,用的是java序列化也就是JDK序列化(ObjetOutputStream)
什么是elasticsearch?
什么是elastic stack(ELK)?
什么是Lucene?
什么是文档和词条?
什么是正向索引?
什么是倒排索引?
分词器的作用是什么?
IK分词器有几种模式?
IK分词器如何拓展词条?如何停用词条?
mapping常见属性有哪些?
type常见的有哪些?
索引库操作有哪些?
文档操作有哪些?
- #创建索引库
- PUT /heima
- {
- "mappings": {
- "properties": {
- "info": {
- "type": "text",
- "analyzer": "ik_smart"
- },
- "email": {
- "type": "keyword",
- "index": false
- },
- "name": {
- "properties": {
- "firstName": {
- "type": "keyword"
- },
- "lastName": {
- "type": "keyword"
- }
- }
- }
- }
- }
- }
-
-
- #查询
- GET /heima
-
-
- #修改,添加字段
- PUT /heima/_mapping
- {
- "properties": {
- "age": {
- "type": "integer"
- }
- }
- }
-
-
- #删除
- DELETE /heima
-
-
-
- #插入文档
- POST /heima/_doc/1
- {
- "info": "程序员",
- "email": "2531994628@qq.com",
- "name": {
- "firstName": "云",
- "lastName": "赵"
- }
- }
-
-
- #查询文档
- GET /heima/_doc/1
-
-
- #删除文档
- DELETE /heima/_doc/1
-
-
- #全量修改文档
- PUT /heima/_doc/1
- {
- "info": "程序员",
- "email": "ZhaoYun@qq.com",
- "name": {
- "firstName": "云",
- "lastName": "赵"
- }
- }
-
-
- #局部修改文档字段
- POST /heima/_update/1
- {
- "doc": {
- "email": "253@qq.com"
- }
- }
索引库操作的基本步骤
- package cn.itcast.hotel.constants;
-
- public class HotelConstants {
-
- public final static String MAPPING_TEMPLATE = "{\n" +
- " \"mappings\": {\n" +
- " \"properties\": {\n" +
- " \"id\": {\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"name\": {\n" +
- " \"type\": \"text\",\n" +
- " \"analyzer\": \"ik_max_word\",\n" +
- " \"copy_to\": \"all\"\n" +
- " },\n" +
- " \"address\": {\n" +
- " \"type\": \"keyword\",\n" +
- " \"index\": false\n" +
- " },\n" +
- " \"price\": {\n" +
- " \"type\": \"integer\"\n" +
- " },\n" +
- " \"score\": {\n" +
- " \"type\": \"integer\"\n" +
- " },\n" +
- " \"brand\": {\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"city\": {\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"standName\": {\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"business\": {\n" +
- " \"type\": \"keyword\",\n" +
- " \"copy_to\": \"all\"\n" +
- " },\n" +
- " \"location\": {\n" +
- " \"type\": \"geo_point\"\n" +
- " },\n" +
- " \"pic\": {\n" +
- " \"type\": \"keyword\",\n" +
- " \"index\": false\n" +
- " },\n" +
- " \"all\": {\n" +
- " \"type\": \"text\",\n" +
- " \"analyzer\": \"ik_max_word\"\n" +
- " }\n" +
- " }\n" +
- " }\n" +
- "}";
- }
- package cn.itcast.hotel;
-
- import cn.itcast.hotel.constants.HotelConstants;
- import org.apache.http.HttpHost;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.client.indices.CreateIndexRequest;
- import org.elasticsearch.client.indices.GetIndexRequest;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.junit.jupiter.api.AfterEach;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import java.io.IOException;
-
-
- @SpringBootTest
- public class HotelIndexTest {
-
- private RestHighLevelClient client;
-
- /**
- * 创建索引库
- * @throws IOException
- */
- @Test
- void testCreatHotelIndex() throws IOException {
- //1、创建Request对象
- CreateIndexRequest request = new CreateIndexRequest("hotel");
- //2、请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是创建索引库的DSL语句
- request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
- //3、发起请求
- client.indices().create(request, RequestOptions.DEFAULT);
- }
-
- /**
- * 删除索引库
- * @throws IOException
- */
- @Test
- void testDeleteHotelIndex() throws IOException{
- //1、创建Request对象
- DeleteIndexRequest request = new DeleteIndexRequest("hotel");
- //2、发起请求,删除索引库
- client.indices().delete(request,RequestOptions.DEFAULT);
- }
-
- /**
- * 判断索引库是否存在
- * @throws IOException
- */
- @Test
- void testExistHotelIndex() throws IOException{
- //1、创建Request对象
- GetIndexRequest request = new GetIndexRequest("hotel");
- //2、发起请求,判断是否存在
- boolean exists = client.indices().exists(request,RequestOptions.DEFAULT);
- //3、输出
- System.out.println(exists ? "索引库已经存在!" : "索引库不存在!");
- }
-
- @BeforeEach
- void setUp(){
- this.client = new RestHighLevelClient(RestClient.builder(
- HttpHost.create("http://192.168.16.3:9200")
- ));
- }
-
- @AfterEach
- void tearDown(){
- try {
- client.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
文档操作的基本步骤:
- package cn.itcast.hotel;
-
- import cn.itcast.hotel.pojo.Hotel;
- import cn.itcast.hotel.pojo.HotelDoc;
- import cn.itcast.hotel.service.IHotelService;
- import com.alibaba.fastjson.JSON;
- import org.apache.http.HttpHost;
- import org.elasticsearch.action.delete.DeleteRequest;
- import org.elasticsearch.action.get.GetRequest;
- import org.elasticsearch.action.get.GetResponse;
- import org.elasticsearch.action.index.IndexRequest;
- import org.elasticsearch.action.update.UpdateRequest;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.junit.jupiter.api.AfterEach;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import java.io.IOException;
-
- @SpringBootTest
- public class HotelDocumentTest {
-
- @Autowired
- private IHotelService hotelService;
-
- @Autowired
- private RestHighLevelClient client;
-
-
- /**
- * 新增文档
- * @throws IOException
- */
- @Test
- void testAddDocument() throws IOException {
-
- //根据id查询酒店数据
- Hotel hotel = hotelService.getById(61083L);
- //转换为文档类型
- HotelDoc hotelDoc = new HotelDoc(hotel);
-
- //1、准备Request对象
- IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
- //2、准备JSON文档
- request.source(hotelDoc, XContentType.JSON);
- //3、发送请求
- client.index(request, RequestOptions.DEFAULT);
- }
-
- /**
- * 查询文档
- * @throws IOException
- */
- @Test
- void GetDocumentById() throws IOException{
- //1、准备request对象
- GetRequest request = new GetRequest("hotel","61083");
- //2、发送请求,得到响应
- GetResponse response = client.get(request,RequestOptions.DEFAULT);
- //3、解析响应结果
- String json = response.getSourceAsString();
-
- // HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
- System.out.println(json);
-
- }
-
- /**
- * 更新文档
- * @throws IOException
- */
- @Test
- void testUpdateDocument() throws IOException {
- //1、准备Request对象
- UpdateRequest request = new UpdateRequest("hotel","61083");
- //2、准备请求参数
- request.doc(
- "price","952",
- "starName","四钻"
- );
- //3、发送请求
- client.update(request,RequestOptions.DEFAULT);
- }
-
- /**
- * 删除文档
- * @throws IOException
- */
- @Test
- void testDeleteDocument() throws IOException{
- //1、准备Request对象
- DeleteRequest request = new DeleteRequest("hotel","61083");
- //2、发送请求
- client.delete(request,RequestOptions.DEFAULT);
- }
-
-
- @BeforeEach
- void setUp(){
- this.client = new RestHighLevelClient(RestClient.builder(
- HttpHost.create("http://192.168.16.3:9200")
- ));
- }
-
- @AfterEach
- void tearDown() throws IOException{
- this.client.close();
- }
-
- }
将数据库中的数据批量导入到索引库中
- /**
- * 批量导入文档
- * @throws IOException
- */
- @Test
- void testBulkDocument() throws IOException{
- //批量查询酒店数据
- List<Hotel> hotels = hotelService.list();
- //1、创建request对象
- BulkRequest request = new BulkRequest();
- //2、准备参数,添加多个新增的Request
- for (Hotel hotel : hotels) {
- //转换文档类型HotelDoc
- HotelDoc hotelDoc = new HotelDoc(hotel);
- //创建新增文档的Request对象
- request.add(new IndexRequest("hotel")
- .id(hotelDoc.getId().toString())
- .source(JSON.toJSONString(hotelDoc),XContentType.JSON));
- }
- //3、发送请求
- client.bulk(request,RequestOptions.DEFAULT);
- }
查询DSL的基本语法是什么?
- ###查询所有
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- }
- }
match和multi_match的区别是什么?
- ###match查询
- GET /hotel/_search
- {
- "query": {
- "match": {
- "all": "如家外滩"
- }
- }
- }
-
-
- ###multi_match查询
- GET /hotel/_search
- {
- "query": {
- "multi_match": {
- "query": "如家外滩",
- "fields": ["brand","name","business"]
- }
- }
- }
精确查询常见的有哪些?
- ### term查询
- GET /hotel/_search
- {
- "query": {
- "term": {
- "city": {
- "value": "广东"
- }
- }
- }
- }
-
-
- ### range查询
- GET /hotel/_search
- {
- "query": {
- "range": {
- "price": {
- "gte": 1000,
- "lte": 2000
- }
- }
- }
- }
- ### geo_distance查询
- GET /hotel/_search
- {
- "query": {
- "geo_distance": {
- "distance": "2km",
- "location": "31.21,121.5"
- }
- }
- }
elasticsearch中的相关性打分算法是什么?
function score query定义的三要素是什么?
- ### function score query 打分算法查询
- GET /hotel/_search
- {
- "query": {
- "function_score": {
- "query": {
- "match": {
- "all": "外滩"
- }
- },
- "functions": [
- {
- "filter": {
- "term": {
- "brand": "如家"
- }
- },
- "weight": 10
- }
- ],
- "boost_mode": "multiply"
- }
- }
- }
bool查询有几种逻辑关系?
利用bool查询实现功能
需求:搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店数据。
- ### bool查询
- GET /hotel/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match": {
- "name": "如家"
- }
- }
- ],
- "must_not": [
- {
- "range": {
- "price": {
- "gt": 400
- }
- }
- }
- ],
- "filter": [
- {
- "geo_distance": {
- "distance": "10km",
- "location": {
- "lat": 31.21,
- "lon": 121.5
- }
- }
- }
- ]
- }
- }
- }
案例1:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序
- ### sort排序
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- },
- "sort": [
- {
- "score": "desc"
- },
- {
- "price": "asc"
- }
- ]
- }
案例2:实现对酒店数据按照到你的位置坐标的距离升序排序
- ### 找到121.5,31.21周围的酒店,距离升序排序
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- },
- "sort": [
- {
- "_geo_distance": {
- "location": {
- "lat": 31.21,
- "lon": 121.5
- },
- "order": "asc",
- "unit": "km"
- }
- }
- ]
- }
from + size:
after search:
scroll:
- ###分页查询
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- },
- "sort": [
- {
- "price": "asc"
- }
- ],
- "from": 20,
- "size": 10
- }
- ###高亮查询,默认情况下,ES搜索字段必须与高亮字段一致
- GET /hotel/_search
- {
- "query": {
- "match": {
- "all": "如家"
- }
- },
- "highlight": {
- "fields": {
- "name": {
- "require_field_match": "false"
- }
- }
- }
- }
- GET /hotel/_search
- {
- "query": {
- "match": {
- "name": "如家"
- }
- },
- "from": 20, //分页开始的位置
- "size": 10, //期望获取的文档总数
- "sort": [
- {
- "price": "desc" //普通排序
- },
- {
- "_geo_distance": { //距离排序
- "location": {
- "lat": 31.21,
- "lon": 121.5
- },
- "order": "asc",
- "unit": "km"
- }
- }
- ],
- "highlight": {
- "fields": { //高亮字段
- "name": {
- "pre_tags": "<em>", //用来标记高亮字段的前置标签
- "post_tags": "<em>", //用来标记高亮字段的后置标签
- "require_field_match": "false" //搜索字段与高亮是否需要匹配,默认是true
- }
- }
- }
- }
查询的基本步骤:
①QueryBuilders来构建查询条件
②传入Request.source()的query()方法
- package cn.itcast.hotel;
-
- import cn.itcast.hotel.pojo.HotelDoc;
- import com.alibaba.fastjson.JSON;
- import org.apache.http.HttpHost;
- import org.elasticsearch.action.search.SearchRequest;
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.index.query.BoolQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
- import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
- import org.elasticsearch.search.sort.SortOrder;
- import org.junit.jupiter.api.AfterEach;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.util.CollectionUtils;
-
- import java.io.IOException;
- import java.util.Map;
-
- @SpringBootTest
- public class HotelSearchTest {
-
- private RestHighLevelClient client;
-
-
- /**
- * 查询所有酒店数据
- * @throws IOException
- */
- @Test
- void testMatchAll() throws IOException{
- //1、准备Request
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- request.source().query(QueryBuilders.matchAllQuery());
- //3、发送请求
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- handlerResponce(response);
- }
-
- /**
- * 全文检索
- * @throws IOException
- */
- @Test
- void testMatch() throws IOException{
- //1、准备Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- request.source().query(QueryBuilders.matchQuery("name","如家"));
- //3、发送请求
- SearchResponse response = client.search(request,RequestOptions.DEFAULT);
- handlerResponce(response);
- }
-
- /**
- * bool查询
- * @throws IOException
- */
- @Test
- void testBool() throws IOException{
- //1、准备Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- //2.1、准备BooleanQuery
- BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
- //2.2、添加term
- queryBuilder.must(QueryBuilders.termQuery("city","上海"));
- //2.3、添加range
- queryBuilder.filter(QueryBuilders.rangeQuery("price").lt(250));
- request.source().query(queryBuilder);
- //3、发送请求
- SearchResponse response = client.search(request,RequestOptions.DEFAULT);
- handlerResponce(response);
- }
-
- /**
- * 排序和分页
- * @throws IOException
- */
- @Test
- void testPageAndSort() throws IOException{
- int page = 1,size = 5;
- //1、创建Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- //2.1、查询所有数据matchAll
- request.source().query(QueryBuilders.matchAllQuery());
- //2.2、sort 排序
- request.source().sort("price", SortOrder.ASC);
- //2.3、page 分页
- request.source().from((page - 1) * size).size(size);
- //3、发送请求
- SearchResponse response = client.search(request,RequestOptions.DEFAULT);
- handlerResponce(response);
- }
-
- /**
- * 高亮显示查询
- * @throws IOException
- */
- @Test
- void testHighLighter() throws IOException{
- //1、创建Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- //2.1、query
- request.source().query(QueryBuilders.matchQuery("all","如家"));
- //2.2、高亮
- request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
- //3、发送请求
- SearchResponse response = client.search(request,RequestOptions.DEFAULT);
- handlerResponce(response);
- }
-
- /**
- * 解析
- * @param response
- */
- private void handlerResponce(SearchResponse response) {
- //4、解析结果
- SearchHits searchHits = response.getHits();
- //4.1查询的总条数
- long total = searchHits.getTotalHits().value;
- System.out.println("共搜索到" + total + "条数据");
- //4.2文档数组
- SearchHit[] hits = searchHits.getHits();
- //4.3遍历
- for (SearchHit hit : hits) {
- //获取文档source
- String json = hit.getSourceAsString();
- //反序列化
- HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
- //获取高亮结果
- Map<String, HighlightField> highlightFields = hit.getHighlightFields();
- if (!CollectionUtils.isEmpty(highlightFields)){
- //根据字段名获取高亮结果
- HighlightField highlightField = highlightFields.get("name");
- if (highlightField != null){
- //获取高亮值
- String name = highlightField.getFragments()[0].string();
- //覆盖非高亮结果
- hotelDoc.setName(name);
- }
- }
- System.out.println("hotelDoc = "+ hotelDoc);
- }
- }
-
- @BeforeEach
- void setUp(){
- this.client = new RestHighLevelClient(RestClient.builder(
- HttpHost.create("http://192.168.16.3:9200")
- ));
- }
-
- @AfterEach
- void tearDown() throws IOException {
- client.close();
- }
- }
搜索、分页、条件过滤、附近的酒店、广告置顶
- package cn.itcast.hotel.service.impl;
-
- import cn.itcast.hotel.mapper.HotelMapper;
- import cn.itcast.hotel.pojo.Hotel;
- import cn.itcast.hotel.pojo.HotelDoc;
- import cn.itcast.hotel.pojo.PageResult;
- import cn.itcast.hotel.pojo.RequestParams;
- import cn.itcast.hotel.service.IHotelService;
- import com.alibaba.fastjson.JSON;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- 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.common.geo.GeoPoint;
- import org.elasticsearch.common.unit.DistanceUnit;
- import org.elasticsearch.index.query.BoolQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
- import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.elasticsearch.search.sort.SortBuilders;
- import org.elasticsearch.search.sort.SortOrder;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
-
- @Service
- public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
-
-
- @Autowired
- private RestHighLevelClient client;
-
- @Override
- public PageResult search(RequestParams params) {
-
- try {
- //1、创建request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- //2.1、query
- bulidBasicQuery(params, request);
- //2.3、分页
- int page = params.getPage();
- int size = params.getSize();
- request.source().from((page - 1) * size).size(size);
- //2.4、排序
- if (params.getLocation() != null && !params.getLocation().equals("")){
- request.source().sort(SortBuilders.geoDistanceSort("location",new GeoPoint(params.getLocation()))
- .order(SortOrder.ASC)
- .unit(DistanceUnit.KILOMETERS));
- }
- //3、发送请求,得到响应
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- //4、解析响应
- return handlerResponce(response);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * 条件过滤
- * @param params 参数
- * @param request 搜索请求
- */
- private void bulidBasicQuery(RequestParams params, SearchRequest request) {
- //2.2构建BooleanQuery
- BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
- String key = params.getKey();
- if (key == null || "".equals(key)) {
- queryBuilder.must(QueryBuilders.matchAllQuery());
- } else {
- queryBuilder.must(QueryBuilders.matchQuery("all", key));
- }
- //2.3、条件过滤
- //2.3.1、城市条件
- if (params.getCity() != null && !params.getCity().equals("")){
- queryBuilder.filter(QueryBuilders.termQuery("city",params.getCity()));
- }
- //2.3.2、品牌条件
- if (params.getBrand() != null && !params.getBrand().equals("")){
- queryBuilder.filter(QueryBuilders.termQuery("brand",params.getBrand()));
- }
- //2.3.3、星级条件
- if (params.getStarName() != null && !params.getStarName().equals("")){
- queryBuilder.filter(QueryBuilders.termQuery("starName",params.getStarName()));
- }
- //2.3.4、价格条件
- if (params.getMinPrice() != null && params.getMaxPrice() != null){
- queryBuilder.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
- }
-
- //3、算分控制
- FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
- //原始查询,相关性算分的查询
- queryBuilder,
- //function score的数组
- new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
- //其中的一个 function score 元素
- new FunctionScoreQueryBuilder.FilterFunctionBuilder(
- //过滤条件
- QueryBuilders.termQuery("isAD",true),
- //算分函数
- ScoreFunctionBuilders.weightFactorFunction(10)
- )
- });
- request.source().query(functionScoreQueryBuilder);
- }
-
- /**
- * 解析
- *
- * @param response
- */
- private PageResult handlerResponce(SearchResponse response) {
- //4、解析结果
- SearchHits searchHits = response.getHits();
- //4.1查询的总条数
- long total = searchHits.getTotalHits().value;
- //4.2文档数组
- SearchHit[] hits = searchHits.getHits();
- //4.3遍历
- List<HotelDoc> hotels = new ArrayList<>();
- for (SearchHit hit : hits) {
- //获取文档source
- String json = hit.getSourceAsString();
- //反序列化
- HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
- //获取排序值
- Object[] sortValues = hit.getSortValues();
- if (sortValues.length > 0){
- Object sortValue = sortValues[0];
- hotelDoc.setDistance(sortValue);
- }
- hotels.add(hotelDoc);
- }
- //4.4、封装返回
- return new PageResult(total,hotels);
- }
-
- }
什么是聚合?
聚合的常见种类有哪些?
参与聚合的字段类型必须是:
aggs代表聚合,与query同级,此时query的作用是?
聚合必须的三要素:
聚合可配置属性有:
- ###聚合功能,自定义排序规则
- GET /hotel/_search
- {
- "size": 0,
- "aggs": {
- "brandAgg": {
- "terms": {
- "field": "brand",
- "size": 10,
- "order": {
- "_count": "asc"
- }
- }
- }
- }
- }
-
- ###聚合功能,限定聚合范围
- GET /hotel/_search
- {
- "query": {
- "range": {
- "price": {
- "lte": 200
- }
- }
- },
- "size": 0,
- "aggs": {
- "brandAgg": {
- "terms": {
- "field": "brand",
- "size": 10,
- "order": {
- "_count": "asc"
- }
- }
- }
- }
- }
- ### 嵌套聚合Metrics
- GET /hotel/_search
- {
- "size": 0,
- "aggs": {
- "brandAgg": {
- "terms": {
- "field": "brand",
- "size": 10,
- "order": {
- "scoreAgg.avg": "desc"
- }
- },
- "aggs": {
- "scoreAgg": {
- "stats": {
- "field": "score"
- }
- }
- }
- }
- }
- }
- /**
- * 数据聚合 多条件聚合
- * @return
- */
- @Override
- public Map<String, List<String>> filters() {
- try {
- //1、创建Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- //2.1、query
- // bulidBasicQuery(params, request);
- //2.2、设置size
- request.source().size(0);
- //2.3、聚合
- bulidAggregation(request);
- //3、发送请求
- SearchResponse response = client.search(request,RequestOptions.DEFAULT);
- //4、解析结果
- Map<String,List<String>> result = new HashMap<>();
- Aggregations aggregations = response.getAggregations();
- List<String> brandList = getAggByName(aggregations, "brandAgg");
- //4.4、放入map
- result.put("品牌",brandList);
- List<String> cityList = getAggByName(aggregations, "cityAgg");
- //4.4、放入map
- result.put("城市",cityList);
- List<String> starList = getAggByName(aggregations, "starAgg");
- //4.4、放入map
- result.put("星级",starList);
- return result;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- /**
- * 封装 聚合
- * @param request
- */
- private void bulidAggregation(SearchRequest request) {
- request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(100));
- request.source().aggregation(AggregationBuilders.terms("cityAgg").field("city").size(100));
- request.source().aggregation(AggregationBuilders.terms("starAgg").field("starName").size(100));
- }
- /**
- * 根据聚合名称获取聚合结果
- * @param aggregations
- * @return
- */
- private List<String> getAggByName(Aggregations aggregations,String aggName) {
- //4.1、根据聚合名称获取聚合结果
- Terms terms = aggregations.get(aggName);
- //4.2、获取buckets
- List<? extends Terms.Bucket> buckets = terms.getBuckets();
- //4.3、遍历
- List<String> list = new ArrayList<>();
- for (Terms.Bucket bucket : buckets) {
- //4.4、获取key
- String key = bucket.getKeyAsString();
- list.add(key);
- }
- return list;
- }
如何使用拼音分词器?
①下载pinyin分词器
②解压并放到elasticsearch的plugin目录
③重启即可
如何自定义分词器?
创建索引时,在settings中配置,可以包含三部分:
拼音分词器注意事项?
为了避免搜索到同音字,搜索时尽量不要使用拼音分词器
- ### 自定义拼音分词器
- PUT /test
- {
- "settings": {
- "analysis": {
- "analyzer": {
- "my_analyzer": {
- "tokenizer": "ik_max_word",
- "filter": "py"
- }
- },
- "filter": {
- "py": {
- "type": "pinyin",
- "keep_full_pinyin": false,
- "keep_joined_full_pinyin": true,
- "keep_original": true,
- "limit_first_letter_length": 16,
- "remove_duplicated_term": true,
- "none_chinese_pinyin_tokenize": false
- }
- }
- }
- }
- , "mappings": {
- "properties": {
- "name": {
- "type": "text",
- "analyzer": "my_analyzer",
- "search_analyzer": "ik_smart"
- }
- }
- }
- }
-
-
- ### 查询自定义分词器数据
- GET /test/_analyze
- {
- "text": ["查询自定义分词器数据"],
- "analyzer": "my_analyzer"
- }
-
-
- ### 添加文档数据
- POST /test/_doc/1
- {
- "id": 1,
- "name": "狮子"
- }
- POST /test/_doc/2
- {
- "id": 2,
- "name": "虱子"
- }
-
-
- ### 查询文档数据
- GET /test/_search
- {
- "query": {
- "match": {
- "name": "掉入狮子笼咋办"
- }
- }
- }
自动补全对字段的要求?
- ### 自动补全的索引库
- PUT /test2
- {
- "mappings": {
- "properties": {
- "title":{
- "type": "completion"
- }
- }
- }
- }
-
-
- ### 示例数据
- POST /test2/_doc
- {
- "title": ["Sony", "WH-1000XM3"]
- }
- POST /test2/_doc
- {
- "title": ["SK-II", "PITERA"]
- }
- POST /test2/_doc
- {
- "title": ["Nintendo", "switch"]
- }
-
-
- ### 自动补全查询
- POST /test2/_search
- {
- "suggest": {
- "title_suggest": {
- "text": "w",
- "completion": {
- "field": "title",
- "skip_duplicates": true,
- "size": 10
- }
- }
- }
- }
- /**
- * 自动补全查询
- * @param prefix
- * @return
- */
- @Override
- public List<String> getSuggestions(String prefix) {
- try {
- //1、创建Request对象
- SearchRequest request = new SearchRequest("hotel");
- //2、准备DSL
- request.source().suggest(new SuggestBuilder().addSuggestion(
- "suggestions",
- SuggestBuilders.completionSuggestion("suggestion")
- .prefix(prefix)
- .skipDuplicates(true)
- .size(10)));
- //3、发送请求
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- //4、解析结果
- Suggest suggest = response.getSuggest();
- //4.1、根据补全名称获取补全结果
- CompletionSuggestion suggestion = suggest.getSuggestion("suggestions");
- //4.2、获取options
- List<CompletionSuggestion.Entry.Option> options = suggestion.getOptions();
- //4.3、遍历
- List<String> list = new ArrayList<>();
- for (CompletionSuggestion.Entry.Option option : options) {
- String text = option.getText().toString();
- list.add(text);
- }
- return list;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
方式一:同步调用
方式二:异步通知
方式三:监听binlog
master eligible节点的作用是什么?
data节点的作用是什么?
coordinator节点的作用是什么?
分布式新增如何确定分片?
分布式查询:
故障转移:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。