SpringCloud微服务(三)RabbitMQ、SpringAMQP、elasticsearch、DSL、MQ、ES详细介绍

news2024/9/20 18:37:05

目录

一、初始MQ

同步调用

异步调用

什么是MQ

执行下面的命令来运行MQ容器:

如果冲突了,可以先查询

RabbitMQ概述 

常见消息模型

HelloWorld案例

二、SpringAMQP

引入依赖

Work Queue 

消费预取限制

​编辑 发布、订阅

发布订阅Fanout Exchange

发布DirectExchange

发布订阅TopicExchange 

消息转化器

MQ代码

三、什么是elasticsearch

 正向索引

倒排索引

文档

索引

概念对比

架构 

 ​编辑

部署单点es

1.2.加载镜像

1.3.运行

命令解释:

2.1.部署

 分词器

2.2.DevTools

kibana中提供了一个DevTools界面:

3.安装IK分词器

3.1.在线安装ik插件(较慢)

3.2.离线安装ik插件(推荐)

1)查看数据卷目录

2)解压缩分词器安装包

3)上传到es容器的插件数据卷中

4)重启容器

5)测试:

3.3 扩展词词典

四、索引库操作 

创建索引库

查看、删除索引库​编辑

修改索引库

 新增文档​编辑

 查看、删除文档​编辑

修改文档

RestClient操作索引库

索引库代码

RestClient操作文档

操作文档代码

DSL 查询文档

 DSL  Query的分类​编辑

DSL Query基本语法

 全文检索查询​编辑

 精确查询​编辑

 地理查询​编辑

相关性算分

 Function Score Query​编辑

复合查询 Boolean Query

 搜索结果处理​编辑

分页

深度分页问题

​编辑高亮 

RestClient查询文档

全文检索查询

精确查询 ​编辑

符合查询

排序和分页

 高亮​编辑


初始MQ

同步调用

异步调用

什么是MQ

执行下面的命令来运行MQ容器:

docker run \
 -e RABBITMQ_DEFAULT_USER=itcast \
 -e RABBITMQ_DEFAULT_PASS=123321 \
 --name mq \
 --hostname mq1 \
 -p 15672:15672 \
 -p 5672:5672 \
 -d \
 rabbitmq:3-management

如果冲突了,可以先查询

RabbitMQ概述 

常见消息模型

HelloWorld案例

 

SpringAMQP

 

引入依赖

 

Work Queue 

 

 

消费预取限制

 发布、订阅

发布订阅Fanout Exchange

发布DirectExchange

发布订阅TopicExchange 

 

 

消息转化器

MQ代码


@Component
public class SpringRabbitListener {

//    @RabbitListener(queues = "simple.queue")
//    public void listenSimpleQueue(String msg){
//        System.out.println("消费者接收到simple.queue的消息:["+msg+"]");
//
//    }

    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue1(String msg) throws InterruptedException {
        System.out.println("消费者1接收到simple.queue的消息:["+msg+"]"+ LocalTime.now());
        Thread.sleep(20);
    }

    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue2(String msg) throws InterruptedException {
        System.err.println("消费者2接收到simple.queue的消息:["+msg+"]"+LocalTime.now());
        Thread.sleep(200);
    }

        @RabbitListener(queues = "fanout.queue1")
    public void listenFanoutQueue1(String msg){
        System.out.println("消费者接收到fanout.queue1的消息:["+msg+"]");

    }

    @RabbitListener(queues = "fanout.queue2")
    public void listenFanoutQueue2(String msg){
        System.out.println("消费者接收到fanout.queue2的消息:["+msg+"]");

    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","blue"}
    ))
    public void listenDirectQueue1(String msg){
        System.out.println("消费者接收到direct.queue1的消息:["+msg+"]");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","yellow"}
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("消费者接收到direct.queue2的消息:["+msg+"]");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void listenTopicQueue1(String msg){
        System.out.println("消费者接收到topic.queue1的消息:["+msg+"]");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void listenTopicQueue2(String msg){
        System.out.println("消费者接收到topic.queue2的消息:["+msg+"]");
    }

    @RabbitListener(queues = "object.queue")
    public void listObjectQueue(Map<String,Object> msg){

        System.out.println("接收object.queue的消息:"+msg);
    }
}

@Configuration
public class FanoutConfig {
    //声明FanoutExchange 交换机
    //itcast.fanout
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("itcast.fanout");
    }
    //声明一个队列fanout.queue1
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }
    //绑定队列1和交换机
    @Bean
     public Binding fanoutBinding1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
        return BindingBuilder
                .bind(fanoutQueue1)
                .to(fanoutExchange);

     }
    //fanout.queue2
    //声明一个队列fanout.queue1
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue2");
    }
    //绑定队列1和交换机
    @Bean
    public Binding fanoutBinding2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
        return BindingBuilder
                .bind(fanoutQueue2)
                .to(fanoutExchange);

    }

    @Bean
    public Queue objectQueue(){
        return new Queue("object.queue");
    }

}


@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

public class PublisherTest {
    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("虚拟机地址");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 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();

    }
}

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAmqpTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSendMessage2SimpleWueue(){
        String queueName = "simple.queue";
        String message = "hello,spring amqp!!!";
        rabbitTemplate.convertAndSend(queueName,message);
    }

    @Test
    public void testSendMessage2WorkQueue() throws InterruptedException {
        String queueName = "simple.queue";
        String message = "hello,message__";
        for ( int i = 1; i <= 50; i++ ) {
            rabbitTemplate.convertAndSend(queueName,message+i);
            Thread.sleep(20);
        }
    }

    @Test
    public void testSendFanoutExchange(){
        //交换机名称
        String exchangeName = "itcast.fanout";
        //消息
        String message = "hello,every one !";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"",message);
    }

    @Test
    public void testSendDirectExchange(){
        //交换机名称
        String exchangeName = "itcast.direct";
        //消息
        String message = "hello,blue !";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"red",message);
    }

    @Test
    public void testSendTopicExchange(){
        //交换机名称
        String exchangeName = "itcast.topic";
        //消息
        String message = "中国NO.1";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"chi.weather",message);
    }

    @Test
    public void testSendObjectExchange(){
        HashMap<String, Object> msg = new HashMap<>();
        msg.put("name","留言2");
        msg.put("age",21);
        //发送消息
        rabbitTemplate.convertAndSend("object.queue",msg);
    }





}

什么是elasticsearch

 

 

 正向索引

倒排索引

 

文档

索引

概念对比

架构 

 

 

部署单点es

因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络:

docker network create es-net

1.2.加载镜像

这里我们采用elasticsearch的7.12.1版本的镜像,这个镜像体积非常大,接近1G。不建议大家自己pull。

课前资料提供了镜像的tar包:

 大家将其上传到虚拟机中,然后运行命令加载即可:

# 导入数据
docker load -i es.tar

同理还有kibana的tar包也需要这样做。

1.3.运行

运行docker命令,部署单点es:

docker run -d \
	--name es \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    -e "discovery.type=single-node" \
    -v es-data:/usr/share/elasticsearch/data \
    -v es-plugins:/usr/share/elasticsearch/plugins \
    --privileged \
    --network es-net \
    -p 9200:9200 \
    -p 9300:9300 \
elasticsearch:7.12.1

命令解释:

  • -e "cluster.name=es-docker-cluster":设置集群名称

  • -e "http.host=0.0.0.0":监听的地址,可以外网访问

  • -e "ES_JAVA_OPTS=-Xms512m -Xmx512m":内存大小

  • -e "discovery.type=single-node":非集群模式

  • -v es-data:/usr/share/elasticsearch/data:挂载逻辑卷,绑定es的数据目录

  • -v es-logs:/usr/share/elasticsearch/logs:挂载逻辑卷,绑定es的日志目录

  • -v es-plugins:/usr/share/elasticsearch/plugins:挂载逻辑卷,绑定es的插件目录

  • --privileged:授予逻辑卷访问权

  • --network es-net :加入一个名为es-net的网络中

  • -p 9200:9200:端口映射配置

在浏览器中输入:http://192.168.150.101:9200 即可看到elasticsearch的响应结果:

 kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习。

2.1.部署

运行docker命令,部署kibana(版本一定要一样)

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601  \
kibana:7.12.1
  • --network es-net :加入一个名为es-net的网络中,与elasticsearch在同一个网络中

  • -e ELASTICSEARCH_HOSTS=http://es:9200":设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch

  • -p 5601:5601:端口映射配置

kibana启动一般比较慢,需要多等待一会,可以通过命令:

docker logs -f kibana

查看运行日志,当查看到下面的日志,说明成功:

 分词器

2.2.DevTools

kibana中提供了一个DevTools界面:

 这个界面中可以编写DSL来操作elasticsearch。并且对DSL语句有自动补全功能。

3.安装IK分词器

3.1.在线安装ik插件(较慢)

# 进入容器内部
docker exec -it elasticsearch /bin/bash

# 在线下载并安装
./bin/elasticsearch-plugin  install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip

#退出
exit
#重启容器
docker restart elasticsearch

3.2.离线安装ik插件(推荐)

1)查看数据卷目录

安装插件需要知道elasticsearch的plugins目录位置,而我们用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:

docker volume inspect es-plugins

显示结果:

[
    {
        "CreatedAt": "2022-05-06T10:06:34+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/es-plugins/_data",
        "Name": "es-plugins",
        "Options": null,
        "Scope": "local"
    }
]

说明plugins目录被挂载到了:/var/lib/docker/volumes/es-plugins/_data这个目录中。

2)解压缩分词器安装包

下面我们需要把课前资料中的ik分词器解压缩,重命名为ik

3)上传到es容器的插件数据卷中

4)重启容器

# 4、重启容器
docker restart es
# 查看es日志
docker logs -f es

5)测试:

IK分词器包含两种模式:

  • ik_smart:最少切分

  • ik_max_word:最细切分

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "我爱学习java太棒了"
}

结果:

{
  "tokens" : [
    {
      "token" : "我",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "爱学习",
      "start_offset" : 1,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "学习",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "java",
      "start_offset" : 4,
      "end_offset" : 8,
      "type" : "ENGLISH",
      "position" : 3
    },
    {
      "token" : "太棒了",
      "start_offset" : 8,
      "end_offset" : 11,
      "type" : "CN_WORD",
      "position" : 4
    },
    {
      "token" : "太棒",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "CN_WORD",
      "position" : 5
    },
    {
      "token" : "了",
      "start_offset" : 10,
      "end_offset" : 11,
      "type" : "CN_CHAR",
      "position" : 6
    }
  ]
}

3.3 扩展词词典

随着互联网的发展,“造词运动”也越发的频繁。出现了很多新的词语,在原有的词汇列表中并不存在。比如:“奥力给”,“传智播客” 等。

所以我们的词汇也需要不断的更新,IK分词器提供了扩展词汇的功能。

1)打开IK分词器config目录:

 2)在IKAnalyzer.cfg.xml配置文件内容添加:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 *** 添加扩展词典-->
        <entry key="ext_dict">ext.dic</entry>
</properties>

索引库操作 

创建索引库

#创建索引库
PUT /heihei
{
  "mappings": {
    "properties": {
      "info": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "email": {
        "type": "keyword",
        "index": false
      },
      "name": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "keyword"
          },
           "lastName": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

查看、删除索引库

 

修改索引库

 

 

 

 新增文档

 查看、删除文档

修改文档

 

RestClient操作索引库

 

 

#酒店的mapping
PUT /hotel
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "adress":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword"
      },
      "city":{
        "type": "keyword"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      }
    }
  }
}

索引库代码


public class HotelIndexTest {
    private RestHighLevelClient client;

    @Test
    void testInit(){
        System.out.println(client);
    }
    @Test
    void createHotelIndex() throws IOException {
        //1.创建Request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        //2.准备请求的参数,DSL语句
        request.source(MAPPTING_TEMPLATE, XContentType.JSON);
        //3.发送请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }


    @Test
    void deleteHotelIndex() throws IOException {
        //1.创建Request对象
        DeleteIndexRequest request = new DeleteIndexRequest("hotel");

        //3.发送请求
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

    @Test
    void testExistHotelIndex() throws IOException {
        //1.创建Request对象
        GetIndexRequest request = new GetIndexRequest("hotel");

        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        //3.发送请求
        System.err.println(exists ? "索引库已经存在" : "索引库不存在!");
    }

    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(
                RestClient.builder(HttpHost.create("http://虚拟机地址:es端口号")
                ));
    }

    @AfterEach
    void tearDown()throws IOException{
        this.client.close();
    }
}

RestClient操作文档

 

 

 

操作文档代码


@SpringBootTest
public class HotelDocumentTest {

    @Autowired
    private IHotelService hotelService;

    private RestHighLevelClient client;

    @Test
    void testAddDcoument() throws IOException {
        //根据id查询酒店数据
        Hotel hotel = hotelService.getById(36934L);
        //转化为文档类型
        HotelDoc hotelDoc = new HotelDoc(hotel);

        //1.准备Request对象
        IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
        //2.准备Json文件
        request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
        client.index(request,RequestOptions.DEFAULT);
        //3.发送请求
    }

    @Test
    void testGetDocumentById() throws IOException {
        //1.准备Request
        GetRequest request = new GetRequest("hotel", "36934");
        //2.发送请求,得到响应
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        String json = response.getSourceAsString();

        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println(hotelDoc);

    }

    @Test
    void testRulkRequest() 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);
            //2.准备参数,添加多个新增的Request
            request.add(new IndexRequest("hotel")
                    .id(hotel.getId().toString())
                    .source(JSON.toJSONString(hotelDoc),XContentType.JSON));

        }
        //3.发送请求
        client.bulk(request,RequestOptions.DEFAULT);
    }



    @Test
    void testUpdateDocumentById() throws IOException {
        //1.准备Request
        UpdateRequest request = new UpdateRequest("hotel", "36934");
        //2.准备请求参数
        request.doc(
                "price","952",
                "starName","五钻"
        );
        //2.发送请求,得到响应
        client.update(request, RequestOptions.DEFAULT);
        //3.解析响应结果
    }

    @Test
    void testDeleteDocumentById() throws IOException {

        List<Hotel> list = hotelService.list();
        //循环删除
        for ( Hotel hotel : list ) {
            //1.准备Request
            DeleteRequest request = new DeleteRequest("hotel", hotel.getId().toString());

            //2.发送请求,得到响应
            client.delete(request, RequestOptions.DEFAULT);
        }

        //1.准备Request
        DeleteRequest request = new DeleteRequest("hotel", "36934");

        //2.发送请求,得到响应
        client.delete(request, RequestOptions.DEFAULT);

    }





    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(
                RestClient.builder(HttpHost.create("http://虚机机地址:es端口")
                ));
    }

    @AfterEach
    void tearDown()throws IOException{
        this.client.close();
    }
}

DSL 查询文档

 

 DSL  Query的分类

DSL Query基本语法

 全文检索查询


GET /hotel/_doc/36934

#查询所有
GET /hotel/_search
{
  "query": {
    "match_all": {}
  }
}

#math查询
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "外滩如家"
    }
  }
}

#multi_math查询
GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "外滩如家",
      "fields": ["brand","name","business"]
    }
  }
}

 精确查询

 

#term查询
GET /hotel/_search
{
  "query": {
    "term": {
      "city": {
        "value": "上海"
      }
    }
  }
}

#range查询 几个e代表等于
GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 1000,
        "lte": 3000
      }
    }
  }
}

 地理查询

 

 

#distance查询
GET /hotel/_search
{
  "query": {
    "geo_distance": {
      "distance":"3km",
      "location":"31.219306, 121.445427"
    }
  }
}

相关性算分

 

 Function Score Query

#function score 查询
GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "all": "外滩"
        }
      },
      "functions": [
        {
          
          "filter":{
            "term":{
              "brand":"7天酒店"
            }
          },
          "weight":10
        }
       ],
       "boost_mode":"sum"
      }
    }
  }
 }
}

 

复合查询 Boolean Query

 

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
            }
          }
        }
      ]
    }
  }
}
 

 搜索结果处理

排序


#sort排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
        "score": "desc"
      
    },
    {
      "price": "asc" 
    }
    
  ]
}

#找到121.6122,31.034周围的酒店,距离升序排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 31.034,
          "lon": 121.6122
        },
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

分页

深度分页问题

 

高亮 

 



#分页查询
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
        "price": "asc" 
      
    }
  ],
   "from":10,
    "size":10
}

#高亮显示 默认情况,ES搜索字段必须与高亮字段一致
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  },
  "highlight": {
    "fields": {
      "name":{
        "require_field_match": "false"
      }
    }
  }
}

RestClient查询文档

 

 

 

 

全文检索查询

 

精确查询 

符合查询

排序和分页

 ​​​​​​​高亮

 ​​​​​​​

觉得好的小伙伴记得一键三连哦


public class HotelIsearchTest {
    private RestHighLevelClient client;



    @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);
        //4解析响应
        handleRequest(response);
    }

    /**
     * 全文检索查询
     * @throws IOException
     */
    @Test
    void testMatch() throws IOException {
        //1 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备DSL
        request.source()
                .query(QueryBuilders.matchQuery("all","如家"));
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleRequest(response);
    }

    /**
     * 精确查询、复合查询
     * @throws IOException
     */
    @Test
    void testBool() throws IOException {
        //1 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备DSL
        //2.1准备BooleanQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.2添加term
        boolQuery.must(QueryBuilders.termQuery("city","上海"));
        //2.3添加range
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
        request.source()
                .query(boolQuery);
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleRequest(response);
    }

    /**
     * 排序和分页
     * @throws IOException
     */
    @Test
    void testPageAndSort() throws IOException {
        //页码、每页大小
        int page = 2,size = 5;
        //1 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备DSL
        //2.1query
        request.source()
                .query(QueryBuilders.matchAllQuery());
        //2.2排序sort
        request.source().sort("price", SortOrder.ASC);
        //2.3分页from、size
        request.source().from((page-1) * size).size(5);
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleRequest(response);
    }

    /**
     * 高亮
     * @throws IOException
     */
    @Test
    void testHighlight() throws IOException {

        //1 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2.准备DSL
        //2.1query
        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);
        handleHighlight(response);
    }


    private void handleRequest(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);
            System.out.println("hotelDoc = " + hotelDoc);
        }
        System.out.println(response);
    }

    /**
     * 高亮结果分析
     * @param response
     */
    private void handleHighlight(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);
        }
        System.out.println(response);
    }

    /**
     *  高亮结果解析
     */

    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(
                RestClient.builder(HttpHost.create("http://虚拟机地址:es端口号")
                ));
    }

    @AfterEach
    void tearDown()throws IOException{
        this.client.close();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/729689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

作物计数方法之合并信息生成json标签的方法

在研究农情的方向中&#xff0c;作物计数是一个很重要的方向&#xff0c;前文已经提到了一些要使用的方法 前文链接&#xff1a;作物计数方法汇总_追忆苔上雪的博客-CSDN博客 在研究计数过程中&#xff0c;还需要将上文处理过的数据信息存入json文件方便后续使用&#xff0c;这…

Array.from详解

德玛玩前端 2023-07-07 在以往的开发中&#xff0c;对于Array.from的了解是from是Array的静态方法&#xff0c;可以将类数组和迭代对象转换为数组&#xff0c;可以结合Set集合快速实现数组的去重&#xff0c;一直以为Array,from()只有一个参数&#xff0c;不是传类数组就是可迭…

idea打包项目时报错 There are test failures

出现这个错误时要点击跳过测试类的按钮&#xff0c;图中的这个圆圈&#xff0c;可以看到test已经被划掉了 再点击package打包&#xff0c;成功。

启航RK3588边缘计算之旅:保定飞凌OK3588开发板

启航RK3588边缘计算之旅&#xff1a;保定飞凌OK3588开发板 引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;人们对于能够提供高性能和灵活性的智能设备有着极大的需求。作为人工智能领域的先锋企业&#xff0c;保定飞凌公司在设计和生产高性能处理器方面取得了卓越的…

在服务器从零开始配置conda、pytorch、cv2

疯掉了 希望是最后一次 0.配置WinSCP和PUTTY 在Windows上使用PuTTY进行SSH连接-腾讯云开发者社区-腾讯云 1.配置conda 如何在Linux服务器上安装Anaconda&#xff08;超详细&#xff09;_linux安装anaconda_流年若逝的博客-CSDN博客 实验室远程登录Linux服务器并配置环境_远…

Linux性能优化实践——平均负载

平均负载&#xff08;Load Average&#xff09; 当我们输入uptime命令时&#xff0c; 这里有几个参数&#xff0c;解释如下 0:54 &#xff1a;当前时间&#xff1b;up 50 mins&#xff1a;系统运行时间&#xff1b;2 users&#xff1a;正在登录用户数&#xff1b;load avera…

活动回顾| 萌啦科技亮相第三届东南亚大会,用数据赋能助力东南亚出海新机遇!

“聚焦深耕”资源对接 6月30日&#xff0c;由DNY123东南亚卖家导航主办的聚焦深耕——第三届东南亚电商本地化&品牌资源对接会在深圳圆满结束。 本次对接会以"聚焦深耕"为主题&#xff0c;旨在推动东南亚电商业务的本地化发展&#xff0c;并促进品牌资源的互通与…

考研的尽头是考公?

2022年12月23日&#xff0c;作为中国诞生于互联网的职业考试培训行业市场领导者的粉笔有限公司&#xff08;“粉笔”或“公司”&#xff09; &#xff0c;早前通过港交所上次聆讯后开始招股。 据悉&#xff0c;粉笔计划发售20&#xff0c;000&#xff0c;000股股份&#xff08;…

win系统删除oracle数据文件恢复---惜分飞

有客户联系我们,说win平台下的数据库,在由于空间紧张,在关闭数据库的情况下删除的两个数据文件,导致数据库无法正常访问很多业务表,需要对其进行恢复,查看alert日志发现大概操作,删除文件之后,启动数据库失败 Completed: alter database mount exclusive alter database open E…

十八、Jenkins(centos7)执行接口自动化测试脚本,飞书推送测试结果消息

十八、Jenkins&#xff08;centos7&#xff09;执行接口自动化测试脚本&#xff0c;飞书推送测试结果消息 1.创建 Freestyle project 项目 2. 输入git仓库地址 https://gitee.com/HP_mojin/pytest_allure_request_20220811 3. 增加构建步骤-Execute shell&#xff08;Jenkins…

TiDB架构中有多少个模块?核心的组件是哪个?

TiDB 集群主要包括三个核心组件&#xff1a;TiDB Server&#xff0c;PD Server 和 TiKV Server。此外&#xff0c;还有用于解决用户复杂 OLAP 需求的 TiSpark 组件和简化云上部署管理的 TiDB Operator 组件。 TiDB架构图解 1. TiDB Server TiDB Server 负责接收 SQL 请求&…

【数据结构导论】第 4 章:树和二叉树

目录 一、树的基本概念 &#xff08;1&#xff09;树的定义 &#xff08;2&#xff09;树的逻辑表示 &#xff08;3&#xff09;树的相关术语 &#xff08;4&#xff09;树的基本运算 二、二叉树 &#xff08;1&#xff09;二叉树的基本概念 ① 定义 ② 特点 ③ 二叉…

【玩转 Cloud Studio】- 云编程之旅

Cloud Studio介绍 Cloud Studio 是基于浏览器的集成式开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供稳定的云端工作站。在使用 Cloud Studio 时无需安装&#xff0c;打开浏览器即可快速启动项目。底层资源自动弹性扩缩&#xff0c;极大地节省成本&#xff0c;…

【课程总结】2023中科大-数字图像分析-期末考试试卷回忆版及往年考题汇总

2023中科大-数字图像分析-期末考试试卷回忆版及汇总 写在前面&#xff1a;一&#xff0c;2023-2024春 期末考试题目回忆二&#xff0c;往年考试题目回忆2.1 2017-2018秋2.2 2018-2019秋2.3 2018-2019 春2.4 2019-2020 秋2.5 2019-2020 春2.6 2020-2021 秋2.7 2021-2022 春2.8 2…

物联网会是下一个支柱产业吗?

近年来&#xff0c;物联网 (IoT) 无疑已成为一个重要且快速增长的行业。尽管绝对确定地预测未来具有挑战性&#xff0c;但许多专家和分析师认为&#xff0c;物联网有潜力成为支柱产业&#xff0c;对各个行业产生变革性影响。 物联网是指由可以收集、交换和分析数据的互连设备、…

Python学习笔记(十八)————python包相关

目录 &#xff08;1&#xff09;python包作用 &#xff08;2&#xff09;自定义python包 &#xff08;3&#xff09;导入自定义包 方式一&#xff1a; 方式二&#xff1a; &#xff08;4&#xff09;导入第三方包 ①pip安装 ②PyCharm安装 &#xff08;1&#xff09;pytho…

【数据挖掘】推荐系统(二):基于内容的推荐

五、基于内容的系统 5.1 基本原理 基于内容的系统根据用户偏好和配置文件生成建议。他们尝试将用户与他们以前喜欢的项目相匹配。项目之间的相似程度通常根据用户喜欢的项目的属性来确定。与大多数利用目标用户和其他用户之间的评级的协作过滤模型不同&#xff0c;基于内容的模…

设计模式之模板方法实现抽奖功能

1.项目背景 接到一个需求&#xff0c;实现电商营销模块的圆盘抽奖功能。如果大家有关注市面上的抽奖&#xff0c;大致也是圆盘抽奖、九宫格抽奖&#xff0c;随机抽球等等。尤其是电商行业&#xff0c;会有各种各样的活动&#xff0c;因此也会出现各式各样的抽奖&#xff0c;那…

【InnoDB 存储引擎】15.7.1 InnoDB Locking(锁实验,重要)

文章目录 1 关于 Record Lock 的实验1.1 实验 1&#xff1a;没有主键时的如何锁定1.2 实验 1&#xff08;续&#xff09;&#xff1a;带着问题继续实验1.3 实验 2&#xff1a;有主键时如何锁定 2 关于 Next-Key Lock 的实验2.1 实验 3&#xff1a;如何确定算法的锁定范围2.2 实…

HTML期末作业-精仿故宫模板(HTML+CSS+JavaScript)

期末作业完成&#xff01;我仿了故宫官网&#xff0c;老师给了90分。现在分享给大家&#xff01; 首页包含功能&#xff1a; 轮播图&#xff1a;在首页顶部设置一个可自动轮播的图片展示区域&#xff0c;展示多张宣传图片或产品图片&#xff0c;提升页面的视觉效果和吸引力。…