• ElasticSearch


    在这里插入图片描述

    一、引言


    京东搜索:手机11苹果

    1.1 海量数据

    mysql 单表的数据量达到500w条以后,检索效率就大幅度的下降了。

    ES本身就支持海量数据的检索

    1.2 全文检索

    mysql的模糊查询,只能进行关键字上的“%xxx%”这种模糊查询,但是不能进行分词检索

    ES:本身就支持按照用户输入的关键词进行拆分的查询,并且可以容错(输入错别字的时候,依然可以查询。)

    二、ES概述


    2.1 ES的介绍
    • ES是一个使用Java语言并且基于Lucene编写的搜索引擎框架,他提供了分布式的全文搜索功能,提供了一个统一的基于RESTful风格的WEB接口,官方客户端也对多种语言都提供了相应的API。

    • Lucene:https://lucene.apache.org/ 是apche的顶级项目,提供搜索的基础类库。

    • 全文检索:区别与关系数据库里的模糊查询,可以把用户输入的内容切词后,去分词库比对,然后把匹配的结果进行返回。

    • RESTful风格的WEB接口:GET,POST,PUT,DELETE

    • 应用广泛:github, wiki , jingdong

    2.2 ES的由来
    ES回忆时光
    在这里插入图片描述

    三、 ElasticSearch安装


    3.1 安装ES&Kibana

    yml文件

    # 注意:先执行如下修改,在运行 docker-compose up -d 
    
    Docker安装 elasticsearch 报错max virtual memory areas vm.max_map_count [65530] is too low
    使用下面命令解决:
    cat /etc/sysctl.conf
    vi /etc/sysctl.conf
    添加 一行 
    vm.max_map_count=655360
    
    加载参数
    sysctl -p
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    version: "3.1"
    services:
      elasticsearch:
        image: daocloud.io/library/elasticsearch:6.8.12
        restart: always
        container_name: elasticsearch
        environment: 
          - "ES_JAVA_OPTS=-Xms512m -Xmx512m" #设置使用jvm内存大小
        ports:
          - 9200:9200
      kibana:
        image: daocloud.io/library/kibana:6.8.12
        restart: always
        container_name: kibana
        ports:
          - 5601:5601
        environment:
          - elasticsearch_url=http://elasticsearch:9200
        depends_on:
          - elasticsearch
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    3.2 安装IK分词器

    下载离线安装包

    • 下载IK分词器的地址:https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.8.12/elasticsearch-analysis-ik-6.8.12.zip
    • 上传文件到虚拟机
    • 解压文件
    • 在es容器内创建目录:/usr/share/elasticsearch/plugins/ik
    • 将解压好的所有文件放入es容器内的目录:/usr/share/elasticsearch/plugins/ik
    • 重启ES容器

    直接在线安装(github网络限制,可能连接失败)

    • 进去到ES容器内部,跳转到bin目录下,执行bin目录下的脚本文件:
    • ./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.8.12/elasticsearch-analysis-ik-6.8.12.zip
    • 或者使用如下地址:
    • ./elasticsearch-plugin install http://39.98.95.55/down/elasticsearch-analysis-ik-6.8.12.zip
    • 重启ES的容器,让IK分词器生效。
    • docker-compose restart
    校验IK分词器
    在这里插入图片描述

    四、 ElasticSearch基本操作


    在这里插入图片描述

    4.1 ES的结构
    4.1.1 索引Index,分片和备份
    • ES的服务中,可以创建多个索引。

    • 每一个索引默认被分成5片存储。

    • 每一个分片都会存在至少一个备份分片。

    • 备份的分片应该放在不同的服务器中。

    在这里插入图片描述

    4.1.2 类型 Type

    ES5 : 一个索引下,可以创建多个类型。

    ES6: 一个索引下,只能创建一个类型(type)。

    ES7:取消了type的概念

    Ps:根据版本不同,类型的创建也不同。

    在这里插入图片描述

    4.1.3 文档 Doc

    ES里的文档(Doc),本质上就是一条json字符传数据。

    一个类型下,可以有多个文档。这个文档就类似于MySQL表中的行数据。

    在这里插入图片描述

    4.1.4 属性 Field

    一个文档中,可以包含多个属性。类似于MySQL表中的一行数据存在多个列。

    在这里插入图片描述

    4.2 操作ES的RESTful语法
    • GET请求:
      • http://ip:port/index:查询索引信息
      • http://ip:port/index/type/doc_id:查询指定的文档信息
    • POST请求:
      • http://ip:port/index/type/_search:查询文档,可以在请求体中添加json字符串来代表查询条件
      • http://ip:port/index/type/doc_id/_update:修改文档,在请求体中指定json字符串代表修改的具体信息
    • PUT请求:
      • http://ip:port/index:创建一个索引,需要在请求体中指定索引的信息,类型,结构
      • http://ip:port/index/type/_mappings:代表创建索引时,指定索引文档存储的属性的信息
    • DELETE请求:
      • http://ip:port/index:删除索引
      • http://ip:port/index/type/doc_id:删除指定的文档
    4.3 索引的操作

    https://www.elastic.co/guide/en/elasticsearch/reference/6.8/index.html

    4.3.1 创建一个索引

    语法如下

    # 创建一个索引
    PUT /person
    {
      "settings": {
        "number_of_shards": 5,
        "number_of_replicas": 1
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    4.3.2 查看索引信息

    语法如下

    # 查看索引信息
    GET /person
    
    • 1
    • 2
    查看信息
    在这里插入图片描述
    4.3.3 删除索引

    语法如下

    # 删除索引
    DELETE /person
    
    • 1
    • 2
    4.4 ES中Field可以指定的类型
    • 字符串类型:

      • text:一般被用于全文检索。 将当前Field进行分词。
      • keyword:当前Field不会被分词。
    • 数值类型:

      • long:取值范围为-9223372036854774808~922337203685477480(-2的63次方到2的63次方-1),占用8个字节
      • integer:取值范围为-2147483648~2147483647(-2的31次方到2的31次方-1),占用4个字节
      • short:取值范围为-32768~32767(-2的15次方到2的15次方-1),占用2个字节
      • byte:取值范围为-128~127(-2的7次方到2的7次方-1),占用1个字节
      • double:1.797693e+308~ 4.9000000e-324 (e+308表示是乘以10的308次方,e-324表示乘以10的负324次方)占用8个字节
      • float:3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,e-45表示乘以10的负45次方),占用4个字节
    • 时间类型:

    • date类型,针对时间类型指定具体的格式

    • 布尔类型:

      • boolean类型,表达true和false

    其他的数据类型参考官网:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/mapping-types.html

    4.5 创建索引并指定数据结构

    语法如下

    https://www.elastic.co/guide/en/elasticsearch/reference/6.5/index.html

    # 创建索引,指定数据结构
    PUT /book
    {
      "settings": {
        # 分片数  
        "number_of_shards": 5,
        # 备份数  
        "number_of_replicas": 1
      },
      "mappings": {
        # type 的名称  
        "novel": {
          # 从这里开始指定 field
          "properties": {
            "name": {
              # 字段的类型 ,text ,可以全文检索
              "type": "text",
              # text类型使用的分词器 
              "analyzer": "ik_max_word"
            },
            "author": {
              "type": "keyword"
            },
            "count": {
              "type": "long"
            },
            "on-sale": {
              "type": "date",
              "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
            },
            "descr": {
              "type": "text",
              "analyzer": "ik_max_word"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    4.6 文档的操作

    文档在ES服务中的唯一标识,_index_type_id三个内容为组合,锁定一个文档,操作是添加还是修改。

    4.6.1 新建文档

    自动生成_id

    # 添加文档,自动生成id
    POST /book/novel
    {
      "name": "盘龙",
      "author": "我吃西红柿",
      "count": 100000,
      "on-sale": "2000-01-01",
      "descr": "山重水复疑无路,柳暗花明又一村"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    手动指定_id

    # 添加文档,手动指定id
    PUT /book/novel/1
    {
      "name": "红楼梦",
      "author": "曹雪芹",
      "count": 10000000,
      "on-sale": "1985-01-01",
      "descr": "一个是阆苑仙葩,一个是美玉无瑕"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    查询当前索引下的全部文档数据

    POST /book/novel/_search
    
    # 根据id查询文档信息 
    GET /book/novel/4AZze4IBTWJVgBPuWRch
    
    • 1
    • 2
    • 3
    • 4
    4.6.2 修改文档

    覆盖式修改

    # 添加文档,手动指定id
    PUT /book/novel/1
    {
      "name": "红楼梦",
      "author": "曹雪芹",
      "count": 4353453,
      "on-sale": "1985-01-01",
      "descr": "一个是阆苑仙葩,一个是美玉无瑕"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    doc修改方式

    # 修改文档,基于doc方式
    POST /book/novel/1/_update
    {
      "doc": {
         # 指定上需要修改的field和对应的值
        "count": "1234565"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    4.6.3 删除文档

    根据id删除

    # 根据id删除文档
    DELETE /book/novel/_id
    
    • 1
    • 2

    五、Springboot操作ElasticSearch【重点


    5.1 版本选择

    https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#repositories

    在这里插入图片描述

    导入依赖

          <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-elasticsearchartifactId>
          dependency>
     
    
    • 1
    • 2
    • 3
    • 4
    • 5

    yml配置

    spring:
      elasticsearch:
        rest:
          uris: http://192.168.57.190:9200
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    5.2 操作索引
    5.2.1 创建索引

    代码如下

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    // createIndex 是否随IOC容器启动自动创建索引
    @Document(indexName = "user_info",shards = 1,replicas = 1,createIndex = false)
    public class UserInfo {
        @Id
        @Field(type = FieldType.Long)
        private Long id;
    
        @Field(type = FieldType.Keyword)
        private String name;
    
        @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
        private String remark;
    
        @Field(type = FieldType.Date)
        private Date jobday;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    @SpringBootTest
    public class AppTest {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void createIndex() {
            elasticsearchRestTemplate.createIndex(UserInfo.class);
            elasticsearchRestTemplate.putMapping(UserInfo.class);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    5.2.2 检查索引是否存在

    代码如下

        @Test
        void queryIndex() {
            final boolean b = elasticsearchRestTemplate.indexExists(UserInfo.class);
            System.out.println(b);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    5.2.3 删除索引

    代码如下

        @Test
        public void deleteIndex() {
            elasticsearchRestTemplate.deleteIndex("user_info");
        }
    
    • 1
    • 2
    • 3
    • 4
    5.3 Java操作文档
    5.3.1 添加文档操作

    代码如下

        @Test
        void save() {
            UserInfo userInfo = new UserInfo();
            userInfo.setId(1l);
            userInfo.setName("张三");
            userInfo.setRemark("这是一个测试用户,用的手机是小米手机,没用苹果手机");
            userInfo.setJobday(new Date());
    
            IndexQuery indexQuery = new IndexQueryBuilder()
                    .withId(userInfo.getId().toString())
                    .withObject(userInfo)
                    .build();
    
            //返回值是索引 
            String index = elasticsearchRestTemplate.index(indexQuery);
            System.out.println(index);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    简化方式

    public interface UserRepository extends ElasticsearchRepository<UserInfo, Long> {
    
    }
    
    • 1
    • 2
    • 3
     @Autowired
        UserRepository userRepository;
    
        @Test
        void indexDoc() {
    
            final UserInfo userInfo = new UserInfo();
            userInfo.setId(100l);
            userInfo.setName("张三");
            userInfo.setJobday(new Date());
            userInfo.setRemark("张三是法外狂徒");
    
            userRepository.save(userInfo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    5.3.2 修改文档

    代码如下

        @Test
        void updateDoc() {
            final UserInfo userInfo = new UserInfo();
            userInfo.setId(100l);
            userInfo.setName("张三1");
            userInfo.setJobday(new Date());
            userInfo.setRemark("张三是法外狂徒111");
    
            userRepository.index(userInfo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    5.3.3 删除文档

    代码如下

        @Test
        void deleteDoc() {
            userRepository.deleteById(100l);
        }
    
    • 1
    • 2
    • 3
    • 4
    5.4 Java批量操作文档
    5.4.1 批量添加

    代码如下

    @Test
        void bulkIndex() {
    
            List<IndexQuery> list = new ArrayList<>();
    
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setId(2l);
            userInfo1.setName("李四");
            userInfo1.setRemark("这是一个用户,用的手机是苹果手机");
            userInfo1.setJobday(new Date());
            IndexQuery indexQuery1 = new IndexQueryBuilder()
                    .withId(userInfo1.getId().toString())
                    .withObject(userInfo1)
                    .build();
            list.add(indexQuery1);
    
            UserInfo userInfo2 = new UserInfo();
            userInfo2.setId(3l);
            userInfo2.setName("王五");
            userInfo2.setRemark("这是一个用户wangwu,用的手机是小米手机");
            userInfo2.setJobday(new Date());
            IndexQuery indexQuery2 = new IndexQueryBuilder()
                    .withId(userInfo2.getId().toString())
                    .withObject(userInfo2)
                    .build();
            list.add(indexQuery2);
            list.add(indexQuery2);
    
            elasticsearchRestTemplate.bulkIndex(list);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
     @Test
        void testSaveAll() {
            List<UserInfo> list = new ArrayList<>();
    
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setId(5l);
            userInfo1.setName("李四");
            userInfo1.setRemark("这是一个用户,用的手机是苹果手机");
            userInfo1.setJobday(new Date());
            list.add(userInfo1);
    
            UserInfo userInfo2 = new UserInfo();
            userInfo2.setId(6l);
            userInfo2.setName("王五");
            userInfo2.setRemark("这是一个用户wangwu,用的手机是小米手机");
            userInfo2.setJobday(new Date());
            list.add(userInfo2);
    
            userRepository.saveAll(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    5.4.2 批量删除

    代码如下

    @Test
        void testDeleteBatch() {
            List<UserInfo> list = new ArrayList<>();
    
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setId(5l);
    
            list.add(userInfo1);
    
            UserInfo userInfo2 = new UserInfo();
            userInfo2.setId(6l);
    
            list.add(userInfo2);
            
            userRepository.deleteAll(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    5.5 ElasticSearch 查询数据导入

    创建索引,指定数据结构

    索引名:sms-logs-index

    类型名:sms-logs-type

    结构如下:

    索引结构图
    在这里插入图片描述
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Document(indexName = "sms-logs-index",type = "sms-logs-type",shards = 1,replicas = 1,createIndex = false)
    public class SmsLogs {
    
        @Id
        @Field(type = FieldType.Long)
        private Long id;// 唯一ID 1
        @Field(type = FieldType.Date)
        private Date createDate;// 创建时间
        @Field(type = FieldType.Date)
        private Date sendDate; // 发送时间
        @Field(type = FieldType.Keyword)
        private String longCode;// 发送的长号码
        @Field(type = FieldType.Keyword)
        private String mobile;// 下发手机号
        @Field(type = FieldType.Keyword)
        private String corpName;// 发送公司名称
        @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
        private String smsContent; // 下发短信内容
        @Field(type = FieldType.Integer)
        private Integer state; // 短信下发状态 0 成功 1 失败
        @Field(type = FieldType.Integer)
        private Integer operatorId; // '运营商编号 1 移动 2 联通 3 电信
        @Field(type = FieldType.Keyword)
        private String province;// 省份
        @Field(type = FieldType.Ip)
        private String ipAddr; //下发服务器IP地址
        @Field(type = FieldType.Integer)
        private Integer replyTotal; //短信状态报告返回时长(秒)
        @Field(type = FieldType.Long)
        private Integer fee;  // 费用
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    public interface SmsLogsRepository extends ElasticsearchRepository<SmsLogs, Long> {
    
    }
    
    • 1
    • 2
    • 3
    @SpringBootTest
    public class SmsLogsRepositoryTest {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Autowired
        SmsLogsRepository smsLogsRepository;
    
        @Test
        void createIndex() {
            elasticsearchRestTemplate.createIndex(SmsLogs.class);
            elasticsearchRestTemplate.putMapping(SmsLogs.class);
        }
    
    
        @Test
        void deleteIndxe() {
            elasticsearchRestTemplate.deleteIndex(SmsLogs.class);
        }
    
        @Test
        void genData() {
    
            final ArrayList<SmsLogs> list = new ArrayList<>();
    
            SmsLogs smsLogs1 = new SmsLogs();
            smsLogs1.setMobile("13800000000");
            smsLogs1.setCorpName("途虎养车");
            smsLogs1.setCreateDate(new Date());
            smsLogs1.setSendDate(new Date());
            smsLogs1.setIpAddr("10.126.2.9");
            smsLogs1.setLongCode("10690000988");
            smsLogs1.setReplyTotal(10);
            smsLogs1.setState(0);
            smsLogs1.setSmsContent("【途虎养车】亲爱的张三先生/女士,您在途虎购买的货品(单号TH123456)已 到指定安装店多日," + "现需与您确认订单的安装情况,请点击链接按实际情况选择(此链接有效期为72H)。您也可以登录途 虎APP进入" + "“我的-待安装订单”进行预约安装。若您在服务过程中有任何疑问,请致电400-111-8868向途虎咨 询。");
            smsLogs1.setProvince("北京");
            smsLogs1.setOperatorId(1);
            smsLogs1.setFee(3);
            smsLogs1.setId(1l);
    
            list.add(smsLogs1);
    
            SmsLogs smsLogs2 = new SmsLogs();
            smsLogs2.setMobile("13100000000");
            smsLogs2.setCorpName("盒马鲜生");
            smsLogs2.setCreateDate(new Date());
            smsLogs2.setSendDate(new Date());
            smsLogs2.setIpAddr("10.126.2.9");
            smsLogs2.setLongCode("10660000988");
            smsLogs2.setReplyTotal(15);
            smsLogs2.setState(0);
            smsLogs2.setSmsContent("【盒马】您尾号12345678的订单已开始配送,请在您指定的时间收货不要走开 哦~配送员:" + "刘三,电话:13800000000");
            smsLogs2.setProvince("北京");
            smsLogs2.setOperatorId(2);
            smsLogs2.setFee(5);
            smsLogs2.setId(2l);
            list.add(smsLogs2);
    
            SmsLogs smsLogs3 = new SmsLogs();
            smsLogs3.setMobile("15300000000");
            smsLogs3.setCorpName("滴滴打车");
            smsLogs3.setCreateDate(new Date());
            smsLogs3.setSendDate(new Date());
            smsLogs3.setIpAddr("10.126.2.8");
            smsLogs3.setLongCode("10660000988");
            smsLogs3.setReplyTotal(50);
            smsLogs3.setState(1);
            smsLogs3.setSmsContent("【滴滴单车平台】专属限时福利!青桔/小蓝月卡立享5折,特惠畅骑30天。" + "戳 https://xxxxxx退订TD");
            smsLogs3.setProvince("上海");
            smsLogs3.setOperatorId(3);
            smsLogs3.setFee(7);
            smsLogs3.setId(3l);
            list.add(smsLogs3);
    
            SmsLogs smsLogs4 = new SmsLogs();
            smsLogs4.setMobile("13900000000");
            smsLogs4.setCorpName("招商银行");
            smsLogs4.setCreateDate(new Date());
            smsLogs4.setSendDate(new Date());
            smsLogs4.setIpAddr("10.126.2.8");
            smsLogs4.setLongCode("10690000988");
            smsLogs4.setReplyTotal(50);
            smsLogs4.setState(0);
            smsLogs4.setSmsContent("【招商银行】尊贵的李四先生,恭喜您获得华为P30 Pro抽奖资格,还可领100 元打" + "车红包,仅限1天");
            smsLogs4.setProvince("上海");
            smsLogs4.setOperatorId(1);
            smsLogs4.setFee(8);
            smsLogs4.setId(4l);
            list.add(smsLogs4);
    
            SmsLogs smsLogs5 = new SmsLogs();
            smsLogs5.setMobile("13700000000");
            smsLogs5.setCorpName("中国平安保险有限公司");
            smsLogs5.setCreateDate(new Date());
            smsLogs5.setSendDate(new Date());
            smsLogs5.setIpAddr("10.126.2.8");
            smsLogs5.setLongCode("10690000998");
            smsLogs5.setReplyTotal(18);
            smsLogs5.setState(0);
            smsLogs5.setSmsContent("【中国平安】奋斗的时代,更需要健康的身体。中国平安为您提供多重健康保 障,在奋斗之路上为您保驾护航。退订请回复TD");
            smsLogs5.setProvince("武汉");
            smsLogs5.setOperatorId(1);
            smsLogs5.setFee(5);
            smsLogs5.setId(5l);
            list.add(smsLogs5);
    
            SmsLogs smsLogs6 = new SmsLogs();
            smsLogs6.setMobile("13600000000");
            smsLogs6.setCorpName("中国移动");
            smsLogs6.setCreateDate(new Date());
            smsLogs6.setSendDate(new Date());
            smsLogs6.setIpAddr("10.126.2.8");
            smsLogs6.setLongCode("10650000998");
            smsLogs6.setReplyTotal(60);
            smsLogs6.setState(0);
            smsLogs6.setSmsContent("【北京移动】尊敬的客户137****0000,5月话费账单已送达您的139邮箱," + "点击查看账单详情 http://y.10086.cn/; " + " 回Q关闭通知,关注“中国移动139邮箱”微信随时查账单【中国移动 139邮箱】");
            smsLogs6.setProvince("武汉");
            smsLogs6.setOperatorId(1);
            smsLogs6.setFee(4);
            smsLogs6.setId(6l);
            list.add(smsLogs6);
    
            smsLogsRepository.saveAll(list);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128

    六、 ElasticSearch的各种查询


    6.1 term&terms查询【重点
    6.1.1 term查询

    term的查询是代表完全匹配,搜索之前不会对你搜索的关键字进行分词,对你的关键字去文档分词库中去匹配内容。

    必须是等于,是与分词库比对,不是与值。,若是没有分词库的,就比较值

    select * from sms_logs where provinc = ‘北京’ limit 0,2

    # term查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "from": 0,     # limit ?
      "size": 5,	  # limit x,?
      "query": {
        "term": {
          "province": {
            "value": "北京"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    代码实现方式

    @SpringBootTest
    public class SmsLogsQueryTest {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Autowired
        SmsLogsRepository smsLogsRepository;
    
        @Test
        void term() {
    
            final TermQueryBuilder termQueryBuilder = new TermQueryBuilder("province","北京");
    
            final SearchQuery searchQuery = new NativeSearchQuery(termQueryBuilder);
            // index and type
            searchQuery.addIndices("sms-logs-index");
            searchQuery.addTypes("sms-logs-type");
    
            // 分页参数
            PageRequest pageRequest = PageRequest.of(0,1);
            searchQuery.setPageable(pageRequest);
    
            // 通用查询方法
            elasticsearchRestTemplate.query(searchQuery, new ResultsExtractor<Void>() {
                @Override
                public Void extract(SearchResponse response) {
                    final SearchHits searchHits = response.getHits();
                    final SearchHit[] hits = searchHits.getHits();
                    for (SearchHit hit : hits) {
                        final Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                        System.out.println(sourceAsMap);
                    }
                    return null;
                }
            });
    
        }
    
        @Test
        void term1() {
            final TermQueryBuilder termQueryBuilder = new TermQueryBuilder("province","北京");
    
            final SearchQuery searchQuery = new NativeSearchQuery(termQueryBuilder);
            searchQuery.addIndices("sms-logs-index");
            searchQuery.addTypes("sms-logs-type");
    
            // 分页参数
            PageRequest pageRequest = PageRequest.of(0,1);
            searchQuery.setPageable(pageRequest);
    
            final List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(searchQuery, SmsLogs.class);
            System.out.println(smsLogs.size());
            System.out.println(smsLogs);
        }
    
        @Test
        void term2() {
            // 分页参数
            PageRequest pageRequest = PageRequest.of(0,1);
            final List<SmsLogs> data = smsLogsRepository.findByProvince("北京",pageRequest);
            System.out.println(data.size());
            System.out.println(data);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    6.1.2 terms查询

    terms和term的查询机制是一样,都不会将指定的查询关键字进行分词,直接去分词库中匹配,找到相应文档内容。

    terms是在针对一个字段包含多个值的时候使用。

    term:where province = 北京;

    terms:where province = 北京 or province = ?or province = ?

    where province in (‘北京’,‘山西’,‘武汉’)

    # terms查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "terms": {
          "province": [
            "北京",
            "山西",
            "武汉"
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    代码实现方式

        @Test
        void terms() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"terms\": {\n" +
                    "      \"province\": [\n" +
                    "        \"北京\",\n" +
                    "        \"山西\",\n" +
                    "        \"武汉\"\n" +
                    "      ]\n" +
                    "    }\n" +
                    "  }");
            // 分页参数
            PageRequest pageRequest = PageRequest.of(0,1);
            query.setPageable(pageRequest);
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    6.2 match查询【重点

    match查询属于高层查询,他会根据你查询的字段类型不一样,采用不同的查询方式。

    • 查询的是日期或者是数值的话,他会将你基于的字符串查询内容转换为日期或者数值对待。
    • 如果查询的内容是一个不能被分词的内容(keyword),match查询不会对你指定的查询关键字进行分词。
    • 如果查询的内容时一个可以被分词的内容(text),match会将你指定的查询内容根据一定的方式去分词,去分词库中匹配指定的内容。
    6.2.1 match_all查询

    查询全部内容,不指定任何查询条件。

    # match_all查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "match_all": {}
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码实现方式

        @Test
        void matchAll() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"match_all\": {}\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    6.2.2 match查询

    指定一个Field作为筛选的条件

    查询关键词分词,有一个关键词匹配上内容的分词库,就返回json文档的json

    # match查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "match": { 
          "smsContent": "收货安装"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码实现方式

        @Test
        void match() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"match\": {\n" +
                    "      \"smsContent\": \"收货安装\"\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    6.2.3 布尔match查询

    基于一个Field匹配的内容,采用and或者or的方式连接

    select * from sms_logs where smsContent like ‘%中国%’ and smsContent like ‘%健康%’

    # 布尔match查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "match": {
          "smsContent": {
            "query": "中国 健康",
            "operator": "and"      # 内容既包含中国也包含健康
          }
        }
      }
    }
    
    
    # 布尔match查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "match": {
          "smsContent": {
            "query": "中国 健康",
            "operator": "or"		# 内容包括健康或者包括中国
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    代码实现方式

    @Test
        void booleanMatchQuery() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"match\": {\n" +
                    "      \"smsContent\": {\n" +
                    "        \"query\": \"中国 健康\",\n" +
                    "        \"operator\": \"or\" "+
                    "      }\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    6.2.4 multi_match查询

    match针对一个field做检索,multi_match针对多个field进行检索,多个field对应一个text。

    select * from sms_logs where province = ‘北京’ or smsContent like ‘%北京%’

    # multi_match 查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "multi_match": {
          "query": "北京",					# 指定text
          "fields": ["province","smsContent"]    # 指定field们
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    代码实现方式

        @Test
        void multiMatchQuery() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"multi_match\": {\n" +
                    "      \"query\": \"北京\",\t\t\t\t\t\n" +
                    "      \"fields\": [\"province\",\"smsContent\"]    \n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    6.3 其他查询
    6.3.1 id查询

    根据id查询 where id = ?

    # id查询
    GET /sms-logs-index/sms-logs-type/1
    
    • 1
    • 2

    代码实现方式

        @Test
        void byID() {
            final SmsLogs smsLogs = elasticsearchRestTemplate.queryForObject(GetQuery.getById("1"), SmsLogs.class);
            System.out.println(smsLogs);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    6.3.2 ids查询

    根据多个id查询,类似MySQL中的where id in(id1,id2,id2…)

    # ids查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "ids": {
          "values": ["1","2","3"]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码实现方式

        @Test
        void byIds() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"ids\": {\n" +
                    "      \"values\": [\"1\",\"2\",\"3\"]\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    6.3.3 prefix查询

    前缀查询,可以通过一个关键字去指定一个Field的前缀,从而查询到指定的文档。

    在这些其他查询,是不会对查询关键词进行分词的

    例如:亲爱的王五 就不会拆,只会在词库里找 亲爱的王五为前缀的词汇所对应的json文档

    where name like ‘途虎%’

    #prefix 查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "prefix": {
          "corpName": {
            "value": "途虎"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    代码实现方式

        @Test
        void findByPrefix() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"prefix\": {\n" +
                    "      \"corpName\": {\n" +
                    "        \"value\": \"途虎\"\n" +
                    "      }\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    6.3.4 fuzzy查询

    模糊查询,我们输入字符的大概,ES就可以去根据输入的内容大概去匹配一下结果。score

    # fuzzy查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "fuzzy": {
          "corpName": {
            "value": "盒马先生",
            "prefix_length": 2			# 指定前面几个字符是不允许出现错误的
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    代码实现方式

        @Test
        void fuzzy() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"fuzzy\": {\n" +
                    "      \"corpName\": {\n" +
                    "        \"value\": \"盒马先生\",\n" +
                    "        \"prefix_length\": 2\t\t\t\n" +
                    "      }\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    6.3.5 wildcard查询

    通配查询,和MySQL中的like是一个套路,可以在查询时,在字符串中指定通配符*和占位符?

    where name like ‘%中国%’

    # wildcard 查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "wildcard": {
          "corpName": {
            "value": "中国*"    # 可以使用*和?指定通配符和占位符
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    代码实现方式

        @Test
        void wildCard() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"wildcard\": {\n" +
                    "      \"corpName\": {\n" +
                    "        \"value\": \"中国*\"    " +
                    "      }\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    6.3.6 range查询

    范围查询,只针对数值类型,对某一个Field进行大于或者小于的范围指定

    # range 查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "range": {
          "fee": {
            "gt": 5,
            "lte": 10
             # 可以使用 gt:>      gte:>=     lt:<     lte:<=
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    代码实现方式

    
    
    • 1
    6.3.7 regexp查询

    正则查询,通过你编写的正则表达式去匹配内容。

    regexp 里 这里例子 mobile它是 keywords类型 所以不会拆词,用正则规定匹配词库,匹配上就成功,返回json文档

    Ps:prefix,fuzzy,wildcard和regexp查询效率相对比较低,要求效率比较高时,避免去使用

    # regexp 查询
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "regexp": {
          "mobile": "180[0-9]{8}"    # 编写正则
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码实现方式

    
    
    • 1
    6.4 复合查询
    6.4.1 bool查询

    复合过滤器,将你的多个查询条件,以一定的逻辑组合在一起。

    • must: 所有的条件,用must组合在一起,表示And的意思
    • must_not:将must_not中的条件,全部都不能匹配,标识Not的意思
    • should:所有的条件,用should组合在一起,表示Or的意思
    # smsContent必须中包含中国和平安
    # 运营商必须不是联通
    # 省份可以为武汉或者北京,但不强求(给结果加分)
    
    
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "smsContent": "中国"
              }
            },
            {
              "match": {
                "smsContent": "平安"
              }
            }
          ],
          "should": [
            {
              "term": {
                "province": {
                  "value": "北京"
                }
              }
            },
            {
              "term": {
                "province": {
                  "value": "武汉"
                }
              }
            }
          ],
          "must_not": [
            {
              "term": {
                "operatorId": {
                  "value": "2"
                }
              }
            }
          ]
    
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    代码实现方式

     @Test
        void BoolQuery() {
            StringQuery query = new StringQuery("{\n" +
                    "    \"bool\": {\n" +
                    "      \"must\": [\n" +
                    "        {\n" +
                    "          \"match\": {\n" +
                    "            \"smsContent\": \"中国\"\n" +
                    "          }\n" +
                    "        },\n" +
                    "        {\n" +
                    "          \"match\": {\n" +
                    "            \"smsContent\": \"平安\"\n" +
                    "          }\n" +
                    "        }\n" +
                    "      ],\n" +
                    "      \"should\": [\n" +
                    "        {\n" +
                    "          \"term\": {\n" +
                    "            \"province\": {\n" +
                    "              \"value\": \"北京\"\n" +
                    "            }\n" +
                    "          }\n" +
                    "        },\n" +
                    "        {\n" +
                    "          \"term\": {\n" +
                    "            \"province\": {\n" +
                    "              \"value\": \"武汉\"\n" +
                    "            }\n" +
                    "          }\n" +
                    "        }\n" +
                    "      ],\n" +
                    "      \"must_not\": [\n" +
                    "        {\n" +
                    "          \"term\": {\n" +
                    "            \"operatorId\": {\n" +
                    "              \"value\": \"2\"\n" +
                    "            }\n" +
                    "          }\n" +
                    "        }\n" +
                    "      ]\n" +
                    "\n" +
                    "    }\n" +
                    "  }");
    
            List<SmsLogs> smsLogs = elasticsearchRestTemplate.queryForList(query, SmsLogs.class);
            smsLogs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    6.4.2 boosting查询

    boosting查询可以帮助我们去影响查询后的score。

    • positive:只有匹配上positive的查询的内容,才会被放到返回的结果集中。
    • negative:如果匹配上和positive并且也匹配上了negative,就可以降低这样的文档score。
    • negative_boost:指定系数,必须小于1.0

    关于查询时,分数是如何计算的:

    • 搜索的关键字在文档中出现的频次越高,分数就越高
    • 指定的文档内容越短,分数就越高
    • 我们在搜索时,指定的关键字也会被分词,这个被分词的内容,被分词库匹配的个数越多,分数越高
    # boosting查询  收货安装
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "boosting": {
          "positive": {
            "match": {
              "smsContent": "收货安装"
            }
          },
          "negative": {
            "match": {
              "smsContent": "王五"
            }
          },
          "negative_boost": 0.5
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    # 把包含指定的关键字的文档的分数提高
    
    POST /sms-logs-index/sms-logs-type/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "term": {
                "province": {
                  "value": "北京"
                }
              }
            },
            {
              "term": {
                "province": {
                  "value": "武汉",
                    #这是乘法,乘以原来的分数 1.1631508*3=3.4894524
                  "boost": 3
                }
              }
            }
          ]
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    代码实现方式

    
    
    • 1

    让京东自营和小米得分增加

    POST /user_info/_search
    {
      "query": {
        "bool": {
          "must": [
            {"match": {
              "remark": "手机"
            }}
          ],
          "should": [
            {"match": {
              "producttype": "京东自营"
            }},
            {
              "match": {
                "producttype": {
                  "query": "小米",
                  "boost": 20
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    七、面试题

    什么是倒排索引(实现全文检索功能的底层数据结构)

    将存放的数据,以一定的方式进行分词,并且将分词的内容存放到一个单独的分词库中。

    当用户去查询数据时,会将用户的查询关键字进行分词。

    然后去分词库中匹配内容,最终得到数据的id标识。

    根据id标识去存放数据的位置拉取到指定的数据。

    举例:对如下数据建立倒排索引。

    ES中存储数据,没一条数据,都是一个JSON字符串,{“id”:“1”,“content”:“xxxxxadfaaf”}

    把content字段指定为text类型

    当向ES中写入一条json数据时,如果某个字段的类型为text,则ES会自动构建该字段内容的倒排索引

    每个字段都有词库,keywords就是本身不分词的词库,text 是分词的词库,每个字段分分隔离。

    重复的词,不添加地址进词库。

    原理:就是拿词去与 所对应字段 的 词库 进行对比,有对应的就返回 json 文档。

  • 相关阅读:
    Docker部署
    逆向学习记录(4)adb
    2022年华中杯数学建模挑战赛B题量化投资问题求解全过程文档及程序
    颗粒归仓水稻总体产量5500吨 国稻种芯-洪江:怀化水稻秋收
    在word、ppt、excel编辑软件标题栏顶部左上角加入自定义功能:另存为、导出PDF
    基于PHP的店家服务与管理交互平台
    计算机网络期末复习-Part2
    笔记本电脑里的微信文件数据误删了 如何恢复?
    Android驱动框架整理之device框架
    这就是跨域吧(个人理解)
  • 原文地址:https://blog.csdn.net/qq_53374893/article/details/132909671