资讯详情

es 安装以及api

一、引言


1.1 海量数据

在海量数据中执行搜索功能时,如果使用MySQL,效率太低

1.2 全文检索

在海量数据中执行搜索功能时,如果使用MySQL,效率太低

1.3 高亮显示

我想用红色字体显示搜索关键字和亮点

elasticsearch基本操作(ES7.x入门)_小诸葛博客博客-CSDN博客_es7 分组查询..%22%7D&request_id=165816120716780366598284&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-123939544-null-null.142v32new_blog_pos_by_title,185v2control&utm_term=es 7.x&spm=1018.2226.3001.4187

二、ES概述


2.1 ES的介绍

  • ES是一个使用( Apache Lucene - Welcome to Apache Lucene/ )他提供了分布式全文搜索功能统一的搜索引擎框架RESTful风格的WEB接口和官方客户端也为各种语言提供了相应的服务API支持

  • Lucene:Lucene搜索引擎本身就是底层

  • 分布式:ES主要是突出他的横向扩展能力

  • 全文搜索:将单词分成单词,并将单个单词统一放入单词库。搜索时,根据关键字搜索单词库,找到匹配的内容(倒置索引,以下解释)

  • RESTful风格的WEB接口:操作ES很简单,只需要发送一个HTTP根据不同的请求模式和不同的携带参数,可以执行相应的功能

  • 应用广泛:Github.com,WIKI,Gold Man等用ES,每天维护近10次TB的数据

  • 更详细的介绍,可以百度搜索es官方文件或中文文件权威指南等↓

    1Getting Started | Elasticsearch Reference [6.0] | Elastic

    2Elasticsearch: 权威指南 | Elastic

2.2 ES的由来

ES回忆时光

##

2.3 ES和Solr

  • Solr查询死数据时,速度相对ES更快,但如果数据实时更改,Solr查询速度会大大降低,ES查询效率基本不变

  • Solr建筑需要依赖Zookeeper帮助管理,而ES支持集群建设,不需要第三方介入

  • 最开始Solr社区可以说很受欢迎,但国内文件不多,在ES出现之后,ES社区人气直线上升,ES文档非常健全

  • ES对现在的云计算和大数据也支持的特别好

2.4 倒排索引

详细介绍倒排索引↓

假设有两篇文章1号和2号:

文章1的内容是:老超在卡门工作,我也是。

文章2的内容是:小超在鼓楼工作。

首先,获得这两篇文章的关键词。如果我们把文章看作一个字符串,我们需要在字符串中获得所有的单词,即分词。在分词时,忽略在、和其他毫无意义的介词,以及可以过滤的标点符号。

文章1号
文章2号

接下来,有了关键词,我们就可以建立倒排索引了。以上对应关系是:文章号对文章中的所有关键词。倒排索引将这种关系转换为: 关键词对拥有关键词的所有文章号。

文章1,文章2倒排后变成

通常只知道哪些文章中出现关键词是不够的,我们还需要知道文章中出现关键词的次数和位置,通常有两个位置:

a.字符位置,即记录文章中的第几个字符(优点是关键字明显时定位快)

b.关键词位置,即记录这个词是文章中的第一个关键词(优点是节省索引空间和短语(phase)查询快)

加上频率和位置信息,我们的索引结构变成了以下几种方式↓

说白了,倒排索引就是把搜索的关键词提取出来给索引,而不是像以前那样和所有其他内容逐一比较,就像查字典一样↑

三、 ElasticSearch安装


3.1 安装ES&Kibana

下面启动es,无法访问地址栏输入地址,查看容器启动日志,发现,es报ERROR,

所以要做以下修改↓

这里的配置需要切换修改root用户需要在这里修改/etc/sysctl.conf为了完成设置,修改本文件的最大过程是es要求的值

root用户修改配置sysctl.conf

vim /etc/sysctl.conf

添加以下配置

vm.max_map_count=655360

执行命令

sysctl -p

重新启动容器

docker-compose.yml

version: "3.1" services:   elasticsearch:    image: daocloud.io/library/elasticsearch:6.5.4    restart: always    container_name: elasticsearch    ports:     - 9200:9200   kibana:    image: daocloud.io/library/kibana:6.5.4    restart: always    container_name: kibana    ports:     - 5601:5601    environment:     - elasticsearch_url=http://10.20.159.25:9200    depends_on:     - elasticsearch

上面的depends_on:指的是kb依赖以下指定es服务

流程如下↓

1进入/opt文件夹创建yml然后编辑文件,复制笔记配置内容,启动容器↓

上述代码如下↓

[root@localhost ~]# cd /opt [root@localhost opt]# ls containerd  docker_mysql_tomcat  docker_nginx  docker_nginx_cluster  docker_redis  [root@localhost opt]# mkdir docker_es [root@localhost opt]# cd docker_es/ [root@localhost docker_es]# vi docker-compose.yml [root@localhost docker_es]# ls docker-compose.yml [root@localhost docker_es]# docker-composeup -d

2输入Linux服务器的ip和es端口9200,测试es服务器是否安装成功,发现输入地址es服务器死活访问不了,↓

通过输入编排日志们命令加上-f参数来查看容器启动日志,看看es服务器是否启动成功,

通过查看日志发现,es报ERROR了,所以要做上面一开头的修改↕

上面报错看开头也行,或者这里直接操作下面的代码↓

[root@localhost ~]# vi /etc/sysctl.conf
# sysctl.conf配置文件打开都是注释,增加配置如下↓
vm.max_map_count=655360
​
# 编辑完上面文件保存退出,执行下面命令sysctl -p↓
[root@localhost ~]# sysctl -p
vm.max_map_count = 655360
​
# 最后重启容器后,稍等一点时间,就可以去访问es服务器了↓
[root@localhost ~]# cd/opt/docker_es/
[root@localhost docker_es]# ls
docker-compose.yml
​
[root@localhost docker_es]# docker-compose restart

3输入Linux服务器的ip和es图形化客户端kb端口5601,测试kb是否安装成功↓

3.2 安装IK分词器

  • es默认的分词器对中文分词不太友好,所以要安装一个对中文分词友好的安装IK分词器↓

  • 下载IK分词器的地址:https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip

  • 由于网络问题采用国内的路径去下载↓

  • 进去到ES容器内部,跳转到bin目录下,执行bin目录下的脚本文件:

  • ./elasticsearch-plugin install http://tomcat01.qfjava.cn:81/elasticsearch-analysis-ik-6.5.4.zip

  • 重启ES的容器,让IK分词器生效。

  • 流程如下↓

    1进入es容器内部,找到bin目录里面的插件文件夹,用插件命令访问http地址去安装ik分词器↓

    2安装完要确认y,然后记住要重启es容器才能让插件生效,这点跟idea安装lombok插件重启巧记理解即可↓

    3打开kb,测试效果,分词器analyzer赋值为ik最大分词ik_max_word,写法不会可以百度或者github搜索↓

校验IK分词器

默认使用 "analyzer": "standard"标准分词器

上面的文字不会,直接打有部分提示,或者抄下面即可↓
POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "我是中国人"
}

四、 ElasticSearch基本操作


4.1 ES的结构

4.1.1 索引Index,分片和备份

索引是ElasticSearch存放数据的地方,可以理解为关系型数据库中的一个数据库。事实上,我们的数据被存储和索引在分片(shards)中,索引只是一个,把一个或多个分片分组在一起的逻辑空间。然而,这只是一些内部细节——我们的程序完全不用关心分片。对于我们的程序而言,文档存储在索引(index)中。剩下的细节由Elasticsearch关心既可(

  • ES的服务中,可以创建多个索引。

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

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

  • 备份分片默认不会帮助检索数据,当ES检索压力特别大的时候,备份分片才会帮助检索数据。

  • 备份的分片必须放在(不要把所有的鸡蛋都放在同一个篮子的道理)。

索引分片备份

4.1.2 类型 Type

类型用于区分同一个索引下不同的数据类型,相当于关系型数据库中的表。在Elasticsearch中,我们使用相同类型(type)的文档表示相同的“事物”,因为他们的数据结构也是相同的。每个类型(type)都有自己的映射(mapping)或者结构定义,就像传统数据库表中的列一样。所有类型下的文档被存储在同一个索引下,但是类型的映射(mapping)会告诉Elasticsearch不同的文档如何被索引。

es 6.0 开始不推荐一个index下多个type的模式,并且会在 7.0 中完全移除。在 6.0 的index下是无法创建多个type的

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

类型

4.1.3 文档 Doc

文档是ElasticSearch中存储的实体,类比关系型数据库,每个文档相当于数据库表中的一行数据。 在Elasticsearch中,文档(document)这个术语有着特殊含义。它特指最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中)。

一个类型下,可以有多个文档。这个文档就类似于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:删除对应id的文档

4.3 索引的操作

4.3.1 创建一个索引

语法如下

# 创建一个索引
PUT /person
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

结果如下↓

4.3.2 查看索引信息

语法如下

# 查看索引信息
GET /person

查询结果如下↓

还可以点击kb的管理来查看↓

查看信息
health:健康的情况,正常的情况下es的健康状态是绿色。
status:状态
Primaries:分片数量
Replicas:备份数量
Docs count:文档数量

这里新建的索引健康状态是黄色是因为es默认会把备份的分片放到其他服务器上面,但是目前我们是单机版找不到其他的es服务器所以是黄色而已。

4.3.3 删除索引

语法如下

# 删除索引
DELETE /person

删除结果如下↓

也可以点击kb的管理来删除↓

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个字节

    • half_float:精度比float小一半。

    • scaled_float:根据一个long和scaled来表达一个浮点型,long-345,scaled-100 -> 3.45

  • 时间类型:

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

  • 布尔类型:

    • boolean类型,表达true和false

  • 二进制类型:

    • binary类型暂时支持Base64 encode string

  • 范围类型:

    • long_range:赋值时,无需指定具体的内容,只需要存储一个范围即可,指定gt,lt,gte,lte

    • integer_range:同上

    • double_range:同上

    • float_range:同上

    • date_range:同上

    • ip_range:同上

  • 经纬度类型:

    • geo_point:用来存储经纬度的

  • ip类型:

    • ip:可以存储IPV4或者IPV6

其他的数据类型参考官网:Field datatypes | Elasticsearch Guide [6.5] | Elastic

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

语法如下

# 创建索引,指定数据结构
PUT /book
{
  "settings": {
    # 分片数
    "number_of_shards": 5,
    # 备份数
    "number_of_replicas": 1
  },
  # 指定数据结构
  "mappings": {
    # 类型 Type
    "novel": {
      # 文档存储的Field
      "properties": {
        # Field属性名
        "name": {
            # 类型
          "type": "text",
            # 指定分词器
          "analyzer": "ik_max_word",
            # 指定当前Field可以被作为查询的条件
          "index": true ,
            # 是否需要额外存储,一般不需要,可以通过其他关键字比如_source查出来
          "store": false 
        },
        "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"
        }
      }
    }
  }
}
PUT /book
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  },
  "mappings": {
    "novel": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "ik_max_word",
          "store": false 
        },
        "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"
        }
      }
    }
  }
}

结果如下↓

4.6 文档的操作

文档是ES服务中的唯一标识,_index_type_id三个内容为组合,定一个文档,如果不存在就添加,否则就是修改。

4.6.1 新建文档

自动生成_id,在路径/下不写id,es给你自动生成,写了比如/1就用你指定的id1,很容易理解↓

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

结果如下↓

手动指定_id

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

结果如下↓

4.6.2 修改文档

覆盖式修改,覆盖所有

# 添加文档,手动指定id,除了添加,第二次就是就是覆盖式修改
PUT /book/novel/1
{
  "name": "红楼梦",
  "author": "曹雪芹",
  "count": 4353453,
  "on-sale": "1985-01-01",
  "descr": "一个是阆苑仙葩,一个是美玉无瑕"
}

doc修改方式,修改某个

# 修改文档,基于doc方式
POST /book/novel/1/_update
{
  "doc": {
    "count": "1234565"
  }
}

结果如下↓

查看修改的具体数据,图形化界面步骤↓

1点击管理,在打开界面点击索引匹配↓

2点击创建索引,然后输入索引的名字book,点下一步↓

3点击下拉三角,不知道选什么就选不知道,点下一步↓

4点击发现,就能查到发现的数据的详细结果了↓

5点击发现,就能查到发现的数据的详细结果了↓

4.6.3 删除文档

根据id删除

# 根据id删除文档,下面这个au1kkHoB7Xrpe4LJZRou是之前不指定自动生成的id,如果是手动指定的比如1,就写1
DELETE /book/novel/I8iXnnoB3j5F3DdMxsYB

结果如下↓

点击发现按钮,找到盘龙那条数据的id,执行删除,再回到发现查看,发现数据没了,删除成功↓

1

2

五、Java操作ElasticSearch【重点


5.1 Java连接ES

创建Maven工程Java基础工程比如起名叫es↓

查找es和es高级api依赖,打开maven仓库官网搜索即可,点击里面找到和Linux服务器安装的对应版本6.5.4↓

导入依赖↓

<dependencies>
    <!--        1. elasticsearch-->
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>6.5.4</version>
    </dependency>
​
    <!--        2. elasticsearch的高级API-->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>6.5.4</version>
    </dependency>
​
    <!--        3. junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
​
    <!--        4. lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.22</version>
    </dependency>
</dependencies>

创建工具类,用来连接ES服务器

package com.qf.utils;
​
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
​
public class ESClient {
    public static RestHighLevelClient getClient(){
        // 创建HttpHost对象
        HttpHost httpHost = new HttpHost("10.20.100.186",9200);//连接Linux服务器安装的es和ip和端口
​
        // 创建RestClientBuilder
        RestClientBuilder clientBuilder = RestClient.builder(httpHost);
​
        // 创建RestHighLevelClient
        RestHighLevelClient client = new RestHighLevelClient(clientBuilder);
​
        // 返回
        return client;
    }
}

测试类调用工具类方法,如果没有报错,表示连上了es服务器↓

package com.qf.utils.test;
​
import com.qf.utils.ESClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.Test;
​
public class Demo01 {
    @Test
    public void testConnect() {
        RestHighLevelClient client = ESClient.getClient();//.var,org.elasticsearch.client.RestHighLevelClient@61009542
        System.out.println(client);
        System.out.println("测试类调用工具类方法,如果没有报错,表示连上了es服务器");
    }
}

5.2 Java操作索引

API 说明
Settings.Builder 封装了settings中的信息
XContentBuilder 封装了mapping中的信息
CreateIndexRequest 封装mapping和settins,index,type
RestHighLevelClient java访问es服务器的客户端
IndicesClient 索引的客户端
CreateIndexResponse 创建完索引后给出响应的对象

5.2.1 创建索引

代码如下,重在理解结构,代码不会写,会抄会用即可↓

public class Demo2 {
    RestHighLevelClient client = ESClient.getClient();
    String index = "person";
    String type = "man";
​
    @Test
    public void createIndex() throws IOException {
        //1. 准备关于索引的settings
        Settings.Builder settings = Settings.builder()
                .put("number_of_shards", 3)
                .put("number_of_replicas", 1);
​
        //2. 准备关于索引的结构mappings
        XContentBuilder mappings = JsonXContent.contentBuilder()
                .startObject()
                    .startObject("properties")
                        .startObject("name")
                            .field("type","text")
                        .endObject()
                        .startObject("age")
                            .field("type","integer")
                        .endObject()
                        .startObject("birthday")
                            .field("type","date")
                            .field("format","yyyy-MM-dd")
                        .endObject()
                    .endObject()
                .endObject();
​
        //3. 将settings和mappings封装到一个Request对象
        CreateIndexRequest request = new CreateIndexRequest(index)
                .settings(settings)
                .mapping(type,mappings);
​
        //4. 通过client对象去连接ES并执行创建索引,缺啥补啥
        CreateIndexResponse resp = client.indices().create(request, RequestOptions.DEFAULT);
​
        //5. 输出
        System.out.println("resp:" + resp.toString());
        //resp:org.elasticsearch.action.admin.indices.create.CreateIndexResponse@c4f729f4
    }
}

5.2.2 检查索引是否存在

代码如下

@Test
public void exists() throws IOException {
    //1. 准备request对象
    GetIndexRequest request = new GetIndexRequest();
    request.indices(index);
​
    //2. 通过client去操作
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
​
    //3. 输出
    System.out.println(exists);//索引index存在返回true,不存在返回false
}

5.2.3 删除索引

代码如下

@Test
public void delete() throws IOException {
    //1. 准备request对象
    DeleteIndexRequest request = new DeleteIndexRequest();
    request.indices(index);
​
    //2. 通过client对象执行
    AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
​
    //3. 获取返回结果
    System.out.println(delete.isAcknowledged());//true
}

5.3 Java操作文档

5.3.1 添加文档操作

代码如下↓

添加依赖↓

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.3</version>
</dependency>

配置实体↓

package com.qf.bean;
​
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
​
import java.util.Date;
​
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    @JsonIgnore//id要忽略转换为json,通过其他Java代码来搞定id生成
    private Integer id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd")//转为json时指定格式
    private Date birthday;
}
public class Demo3 {
    ObjectMapper mapper = new ObjectMapper();//这里用到jackson所以上面要先添加依赖↑
    
    RestHighLevelClient client = ESClient.getClient();
    String index = "person";
    String type = "man";
​
    @Test
    public void createDoc() throws IOException {
        //1. 准备一个json数据
        Person person = new Person(1,"张三",23,new Date());
        String json = mapper.writeValueAsString(person);
​
        //2. 准备一个request对象(其他Java代码来搞定id生成,即手动指定id↓)
        IndexRequest request = new IndexRequest(index,type,person.getId().toString());
        request.source(json, XContentType.JSON);
​
        //3. 通过client对象执行添加
        IndexResponse resp = client.index(request, RequestOptions.DEFAULT);
​
        //4. 输出返回结果
        System.out.println(resp.getResult().toString());
        //添加成功返回的第一次是CREATED,再运行一次是更新是UPDATED
    }
}

结果查询要点击索引匹配,才能点击发现按钮来得到查询的具体数据↓

5.3.2 修改文档

代码如下

 @Test
public void updateDoc() throws IOException {
    //1. 创建一个Map,指定需要修改的内容
    Map<String,Object> doc = new HashMap<String,Object>();
    doc.put("name","张大三"); // 如果id放在map中会把id属性设置到_source里面
    String docId = "1";
​
    //2. 创建request对象,封装数据
    UpdateRequest request = new UpdateRequest(index,type,docId);
    request.doc(doc);
​
    //3. 通过client对象执行
    UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
​
    //4. 输出返回结果
    System.out.println(update.getResult().toString());//UPDATED
}

修改后点击浏览器刷新按钮,数据对比,发现名字更新为张大三了↓

5.3.3 删除文档

代码如下

@Test
public void deleteDoc() throws IOException {
    //1. 封装Request对象
    DeleteRequest request = new DeleteRequest(index,type,"1");
​
    //2. client执行
    DeleteResponse resp = client.delete(request, RequestOptions.DEFAULT);
​
    //3. 输出结果
    System.out.println(resp.getResult().toString());
    //删除成功返回DELETED,再删没有数据返回NOT_FOUND
}

删除后点击浏览器刷新按钮,数据对比,发现确实删除了名字为张大三了这条数据,没有数据了↓

5.4 Java批量操作文档

5.4.1 批量添加

代码如下

@Test
public void bulkCreateDoc() throws IOException {
    //1. 准备多个json数据
    Person p1 = new Person(1,"张三",23,new Date());
    Person p2 = new Person(2,"李四",24,new Date());
    Person p3 = new Person(3,"王五",25,new Date());
​
    String json1 = mapper.writeValueAsString(p1);
    String json2 = mapper.writeValueAsString(p2);
    String json3 = mapper.writeValueAsString(p3);
​
    //2. 创建Request,将准备好的数据封装进去
    BulkRequest request = new BulkRequest();
    
    request.add(new IndexRequest(index,type,p1.getId().toString()).source(json1,XContentType.JSON));
    
    request.add(new IndexRequest(index,type,p2.getId().toString()).source(json2,XContentType.JSON));
    request.add(new IndexRequest(index,type,p3.getId().toString()).source(json3,XContentType.JSON));
​
    //3. 用client执行
    BulkResponse resp = client.bulk(request, RequestOptions.DEFAULT);
​
    //4. 输出结果
    System.out.println(resp.toString());//org.elasticsearch.action.bulk.BulkResponse@3aa078fd
}

图形化界面es客户端kb查询,点击浏览器刷新按钮,发现数据结果如下,增加了三条数据↓

5.4.2 批量删除

代码如下

@Test
public void bulkDeleteDoc() throws IOException {
    //1. 封装Request对象
    BulkRequest request = new BulkRequest();
    
    request.add(new DeleteRequest(index,type,"1"));
    request.add(new DeleteRequest(index,type,"2"));
    request.add(new DeleteRequest(index,type,"3"));
​
    //2. client执行
    BulkResponse resp = client.bulk(request, RequestOptions.DEFAULT);
​
    //3. 输出
    System.out.println(resp);//org.elasticsearch.action.bulk.BulkResponse@196a42c3
}

图形化界面es客户端kb查询,点击浏览器刷新按钮,发现数据结果如下,删除了三条数据,数据没了↓

5.5 ElasticSearch练习,课下操作,这里只是为了方便等下讲的查询数据用↓

创建索引,指定数据结构

索引名:sms-logs-index

类型名:sms-logs-type

结构如下:

索引结构图

5.6 准备数据

导入fastjson依赖,因为下面的Java代码要用到↓

 <!-- 先导入fastJSON,做对象序列化为json字符串等操作 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>

编写实现类SmsLogs↓

package com.qf.bean;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
​
import java.util.Date;
​
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmsLogs {
    private String id;// 唯一ID 1
    private Date createDate;// 创建时间
    private Date sendDate; // 发送时间
    private String longCode;// 发送的长号码
    private String mobile;// 下发手机号
    private String corpName;// 发送公司名称
    private String smsContent; // 下发短信内容
    private Integer state; // 短信下发状态 0 成功 1 失败
    private Integer operatorId; // '运营商编号 1 移动 2 联通 3 电信
    private String province;// 省份
    private String ipAddr; //下发服务器IP地址
    private Integer replyTotal; //短信状态报告返回时长(秒)
    private Integer fee;  // 费用
}

编写测试类Demo4,提供两个方法,分别用来创建索引库,和增加数据↓

package com.qf.test;
​
import com.alibaba.fastjson.JSON;
import com.qf.bean.SmsLogs;
import com.qf.utils.ESClient;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.junit.Test;
​
import java.io.IOException;
import java.util.Date;
​
public class Demo4 {
    RestHighLevelClient client = ESClient.getClient();
    String index = "sms-logs-index";
    String type = "sms-logs-type";
​
    @Test
    public void createSmsLogsIndex() throws IOException {
        //1. settings
        Settings.Builder settings = Settings.builder()
                .put("number_of_shards", 3)
                .put("number_of_replicas", 1);
​
        //2. mapping.
        XContentBuilder mapping = JsonXContent.contentBuilder()
                .startObject()
                .startObject("properties")
                .startObject("createDate")
                .field("type", "date")
                .endObject()
                .startObject("sendDate")
                .field("type", "date")
                .endObject()
                .startObject("longCode")
                .field("type", "keyword")
                .endObject()
                .startObject("mobile")
                .field("type", "keyword")
                .endObject()
                .startObject("corpName")
                .field("type", "keyword")
                .endObject()
                .startObject("smsContent")
                .field("type", "text")
                .field("analyzer", "ik_max_word")
                .endObject()
                .startObject("state")
                .field("type", "integer")
                .endObject()
                .startObject("operatorId")
                .field("type", "integer")
                .endObject()
                .startObject("province")
                .field("type", "keyword")
                .endObject()
                .startObject("ipAddr")
                .field("type", "ip")
                .endObject()
                .startObject("replyTotal")
                .field("type", "integer")
                .endObject()
                .startObject("fee")
                .field("type", "long")
                .endObject()
                .endObject()
                .endObject();
​
        //3. 添加索引.
        CreateIndexRequest request = new CreateIndexRequest(index);
        request.settings(settings);
        request.mapping(type,mapping);
        client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println("OK!!");
    }
​
    @Test
    public void addTestData() throws IOException {
        BulkRequest request = new BulkRequest();
​
        SmsLogs smsLogs = new SmsLogs();
        smsLogs.setMobile("13800000000");
        smsLogs.setCorpName("途虎养车");
        smsLogs.setCreateDate(new Date());
        smsLogs.setSendDate(new Date());
        smsLogs.setIpAddr("10.126.2.9");
        smsLogs.setLongCode("10690000988");
        smsLogs.setReplyTotal(10);
        smsLogs.setState(0);
        smsLogs.setSmsContent("【途虎养车】亲爱的张三先生/女士,您在途虎购买的货品(单号TH123456)已 到指定安装店多日," + "现需与您确认订单的安装情况,请点击链接按实际情况选择(此链接有效期为72H)。您也可以登录途 虎APP进入" + "“我的-待安装订单”进行预约安装。若您在服务过程中有任何疑问,请致电400-111-8868向途虎咨 询。");
        smsLogs.setProvince("北京");
        smsLogs.setOperatorId(1);
        smsLogs.setFee(3);
        request.add(new IndexRequest(index, type, "21").source(JSON.toJSONString(smsLogs), XContentType.JSON));
​
        smsLogs.setMobile("13700000001");
        smsLogs.setProvince("上海");
        smsLogs.setSmsContent("【途虎养车】亲爱的刘红先生/女士,您在途虎购买的货品(单号TH1234526)已 到指定安装店多日," + "现需与您确认订单的安装情况,请点击链接按实际情况选择(此链接有效期为72H)。您也可以登录途 虎APP进入" + "“我的-待安装订单”进行预约安装。若您在服务过程中有任何疑问,请致电400-111-8868向途虎咨 询。");
        request.add(new IndexRequest(index, type, "22").source(JSON.toJSONString(smsLogs), XContentType.JSON));
​
        // -------------------------------------------------------------------------------------------------------------------
​
        SmsLogs smsLogs1 = new SmsLogs();
        smsLogs1.setMobile("13100000000");
        smsLogs1.setCorpName("盒马鲜生");
        smsLogs1.setCreateDate(new Date());
        smsLogs1.setSendDate(new Date());
        smsLogs1.setIpAddr("10.126.2.9");
        smsLogs1.setLongCode("10660000988");
        smsLogs1.setReplyTotal(15);
        smsLogs1.setState(0);
        smsLogs1.setSmsContent("【盒马】您尾号12345678的订单已开始配送,请在您指定的时间收货不要走开 哦~配送员:" + "刘三,电话:13800000000");
        smsLogs1.setProvince("北京");
        smsLogs1.setOperatorId(2);
        smsLogs1.setFee(5);
        request.add(new IndexRequest(index, type, "23").source(JSON.toJSONString(smsLogs1), XContentType.JSON));
​
        smsLogs1.setMobile("18600000001");
        smsLogs1.setProvince("上海");
        smsLogs1.setSmsContent("【盒马】您尾号7775678的订单已开始配送,请在您指定的时间收货不要走开 哦~配送员:" + "王五,电话:13800000001");
        request.add(new IndexRequest(index, type, "24").source(JSON.toJSONString(smsLogs1), XContentType.JSON));
​
        // -------------------------------------------------------------------------------------------------------------------
​
        SmsLogs smsLogs2 = new SmsLogs();
        smsLogs2.setMobile("15300000000");
        smsLogs2.setCorpName("滴滴打车");
        smsLogs2.setCreateDate(new Date());
        smsLogs2.setSendDate(new Date());
        smsLogs2.setIpAddr("10.126.2.8");
        smsLogs2.setLongCode("10660000988");
        smsLogs2.setReplyTotal(50);
        smsLogs2.setState(1);
        smsLogs2.setSmsContent("【滴滴单车平台】专属限时福利!青桔/小蓝月卡立享5折,特惠畅骑30天。" + "戳 https://xxxxxx退订TD");
        smsLogs2.setProvince("上海");
        smsLogs2.setOperatorId(3);
        smsLogs2.setFee(7);
        request.add(new IndexRequest(index, type, "25").source(JSON.toJSONString(smsLogs2), XContentType.JSON));
​
        smsLogs2.setMobile("18000000001");
        smsLogs2.setProvince("武汉");
        smsLogs2.setSmsContent("【滴滴单车平台】专属限时福利!青桔/小蓝月卡立享5折,特惠畅骑30天。" + "戳 https://xxxxxx退订TD");
        request.add(new IndexRequest(index, type, "26").source(JSON.toJSONString(smsLogs2), XContentType.JSON));
​
​
        // -------------------------------------------------------------------------------------------------------------------
​
        SmsLogs smsLogs3 = new SmsLogs();
        smsLogs3.setMobile("13900000000");
        smsLogs3.setCorpName("招商银行");
        smsLogs3.setCreateDate(new Date());
        smsLogs3.setSendDate(new Date());
        smsLogs3.setIpAddr("10.126.2.8");
        smsLogs3.setLongCode("10690000988");
        smsLogs3.setReplyTotal(50);
        smsLogs3.setState(0);
        smsLogs3.setSmsContent("【招商银行】尊贵的李四先生,恭喜您获得华为P30 Pro抽奖资格,还可领100 元打" + "车红包,仅限1天");
        smsLogs3.setProvince("上海");
        smsLogs3.setOperatorId(1);
        smsLogs3.setFee(8);
        request.add(new IndexRequest(index, type, "27").source(JSON.toJSONString(smsLogs3), XContentType.JSON));
​
        smsLogs3.setMobile("13990000001");
        smsLogs3.setProvince("武汉");
        smsLogs3.setSmsContent("【招商银行】尊贵的李四先生,恭喜您获得华为P30 Pro抽奖资格,还可领100 元打" + "车红包,仅限1天");
        request.add(new IndexRequest(index, type, "28").source(JSON.toJSONString(smsLogs3), XContentType.JSON));
​
        // -------------------------------------------------------------------------------------------------------------------
​
        SmsLogs smsLogs4 = new SmsLogs();
        smsLogs4.setMobile("13700000000");
        smsLogs4.setCorpName("中国平安保险有限公司");
        smsLogs4.setCreateDate(new Date());
        smsLogs4.setSendDate(new Date());
        smsLogs4.setIpAddr("10.126.2.8");
        smsLogs4.setLongCode("10690000998");
        smsLogs4.setReplyTotal(18);
        smsLogs4.setState(0);
        smsLogs4.setSmsContent("【中国平安】奋斗的时代,更需要健康的身体。中国平安为您提供多重健康保 障,在奋斗之路上为您保驾护航。退订请回复TD");
        smsLogs4.setProvince("武汉");
        smsLogs4.setOperatorId(1);
        smsLogs4.setFee(5);
        request.add(new IndexRequest(index, type, "29").source(JSON.toJSONString(smsLogs4), XContentType.JSON));
​
        smsLogs4.setMobile("13990000002");
        smsLogs4.setProvince("武汉");
        smsLogs4.setSmsContent("【招商银行】尊贵的王五先生,恭喜您获得iphone 56抽奖资格,还可领5 元打" + "车红包,仅限100天");
        request.add(new IndexRequest(index, type, "30").source(JSON.toJSONString(smsLogs4), XContentType.JSON));
​
        // -------------------------------------------------------------------------------------------------------------------
​
​
        SmsLogs smsLogs5 = new SmsLogs();
        smsLogs5.setMobile("13600000000");
        smsLogs5.setCorpName("中国移动");
        smsLogs5.setCreateDate(new Date());
        smsLogs5.setSendDate(new Date());
        smsLogs5.setIpAddr("10.126.2.8");
        smsLogs5.setLongCode("10650000998");
        smsLogs5.setReplyTotal(60);
        smsLogs5.setState(0);
        smsLogs5.setSmsContent("【北京移动】尊敬的客户137****0000,5月话费账单已送达您的139邮箱," + "点击查看账单详情 http://y.10086.cn/; " + " 回Q关闭通知,关注“中国移动139邮箱”微信随时查账单【中国移动 139邮箱】");
        smsLogs5.setProvince("武汉");
        smsLogs5.setOperatorId(1);
        smsLogs5.setFee(4);
        request.add(new IndexRequest(index, type, "31").source(JSON.toJSONString(smsLogs5), XContentType.JSON));
​
        smsLogs5.setMobile("13990001234");
        smsLogs5.setProvince("山西");
        smsLogs5.setSmsContent("【北京移动】尊敬的客户137****1234,8月话费账单已送达您的126邮箱,\" + \"点击查看账单详情 http://y.10086.cn/; \" + \" 回Q关闭通知,关注“中国移动126邮箱”微信随时查账单【中国移动 126邮箱】");
        request.add(new IndexRequest(index, type, "32").source(JSON.toJSONString(smsLogs5), XContentType.JSON));
        // -------------------------------------------------------------------------------------------------------------------
​
        client.bulk(request, RequestOptions.DEFAULT);
​
        System.out.println("OK!");
    }
​
}

最后点击索引匹配,然后来到发现按钮页面可以查看到添加了很多数据,方便下面用es做各种查询用↓

六、 ElasticSearch的各种查询


6.1 term&terms查询【重点

6.1.1 term查询(分页)

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

# term查询
POST /sms-logs-index/sms-logs-type/_search
{
  "from": 0,     
  "size": 5,      
  "query": {
    "term": {
      "province": {
        "value": "北京"
      }
    }
  }
}

max_score匹配度越高,数据的排名就越靠前↑

代码实现方式

// Java代码实现方式
@Test
public void termQuery() throws IOException {
    //1. 创建Request对象
    SearchRequest request = new SearchRequest(index);
    request.types(type);
​
    //2. 指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.from(0);
    builder.size(5);
    builder.query(QueryBuilders.termQuery("province","北京"));
​
    request.source(builder);
​
    //3. 执行查询
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);
​
    //4. 获取到_source中的数据,并展示
    for (SearchHit hit : resp.getHits().getHits()) {
        Map<String, Object> result = hit.getSourceAsMap();
        System.out.println(result);
    }
}

上面的Java代码的resp.getHits().getHits(),分别对应查询结果下图中的两个hits命中数据↓

6.1.2 terms查询

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

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

term:where province = 北京;

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

# terms查询
POST /sms-logs-index/sms-logs-type/_search
{
  "query": {
    "terms": {
      "province": [
        "北京",
        "山西",
        "武汉"
      ]
    }
  }
}
​
## 返回指定的列
POST /sms-logs-index/sms-logs-type/_search
{
  "_source": ["province","fee"], 
  "query": {
    "terms": {
      "province": [
        "北京",
        "山西",
        "武汉"
      ]
    }
  }
}

代码实现方式

// Java实现
@Test
public void termsQuery() throws IOException {
    //1. 创建request
    SearchRequest request = new SearchRequest(index);
    request.types(type);
​
    //2. 封装查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.termsQuery("province","北京","山西"));
​
    request.source(builder);
​
    //3. 执行查询
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);
​
    //4. 输出_source
    for (SearchHit hit : resp.getHits().getHits()) {
        System.out.println(hit.getSourceAsMap());
    }
}

6.2 match查询【重点

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

  • 查询的是日期或者是数值的话,他会将你基于的字符串查询内容转换为日期或者数值对待。

  • 如果查询的内容是一个不能被分词的内容(keyword),match查询不会对你指定的查询关键字进行分词。

  • 如果查询的内容时一个可以被分词的内容(text),match会将你指定的查询内容根据一定的方式去分词,去分词库中匹配指定的内容。

match查询,实际底层就是多个term查询,将多个term查询的结果给你封装到了一起而已。

6.2.1 match_all查询

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

# match_all查询
POST /sms-logs-index/sms-logs-type/_search
{
  "query": {
    "match_all": {}
  }
}

代码实现方式

//  java代码实现
@Test
public void matchAllQuery() throws IOException {
    //1. 创建Request
    SearchRequest request = new SearchRequest(index);
    request.types(type);
​
    //2. 指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.matchAllQuery());
    builder.size(20);           // ES默认只查询10条数据,如果想查询更多,添加size
    
    request.source(builder);
​
    //3. 执行查询
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);
​
    //4. 输出结果
    for (SearchHit hit : resp.getHits().getHits()) {
        System.out.println(hit.getSourceAsMap());
    }
    
    System.out.println(resp.getHits().getHits().length);
}

6.2.2 match查询

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

# match查询
POST /sms-logs-index/sms-logs-type/_search
{
  "query": {
    "match": {
      "smsContent": "收货安装"
    }
  }
}

代码实现方式

@Test
public void matchQuery() throws IOException {
    //1. 创建Request
    SearchRequest request = new SearchRequest(index);
    request.types(type);
​
    //2. 指定查询条件
    SearchSourceBuilder builder = new SearchSourceBuilder();
    //-----------------------------------------------
    builder.query(QueryBuilders.matchQuery("smsContent","收货安装"));
    //-----------------------------------------------
    request.source(builder);
    //3. 执行查询
    SearchResponse resp = client.search(request, RequestOptions.DEFAULT);
​
    //4. 输出结果
    for (SearchHit hit : resp.getHits(

标签: th矩形电连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台