ElasticSearch基本介绍

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

外文名Elasticsearch

用 途用于分布式全文检索

技术支持通过HTTP使用JSON进行数据索引

主要目的解决人们对于搜索的众多要求

简 称ES

倒排索引

正排索引

在说倒排索引之前我们先说说什么是正排索引。正排索引也称为"前向索引",它是创建倒排索引的基础。 这种组织方法在建立索引的时候结构比较简单,建立比较方便且易于维护;因为索引是基于文档建立的,若是有新的文档加入,直接为该文档建立一个新的索引块,挂接在原来索引文件的后面。若是有文档删除,则直接找到该文档号文档对应的索引信息,将其直接删除。 他适合根据文档ID来查询对应的内容。但是在查询一个keyword在哪些文档里包含的时候需对所有的文档进行扫描以确保没有遗漏,这样就使得检索时间大大延长,检索效率低下。 比如有几个文档及里面的内容,他正排索引构建的结果如下图:

图片.png

优点:工作原理非常的简单。 缺点:检索效率太低,只能在一起简单的场景下使用。

倒排索引

根据字面意思可以知道他和正序索引是反的。在搜索引擎中每个文件都对应一个文件ID,文件内容被表示为一系列关键词的集合(文档要除去一些无用的词,比如’的’这些,剩下的词就是关键词,每个关键词都有自己的ID)。例如“文档1”经过分词,提取了3个关键词,每个关键词都会记录它所在在文档中的出现频率及出现位置。 那么上面的文档及内容构建的倒排索引结果会如下图(注:这个图里没有记录展示该词在出现在哪个文档的具体位置):

图片.png

如何来查询呢?

比如我们要查询‘搜索引擎’这个关键词在哪些文档中出现过。首先我们通过倒排索引可以查询到该关键词出现的文档位置是在1和3中;然后再通过正排索引查询到文档1和3的内容并返回结果。

倒排索引组成

倒排索引主要由单词词典(Term Dictionary)和倒排列表(Posting List)及倒排文件(Inverted File)组成。 他们三者的关系如下图:

图片.png

单词词典(Term Dictionary):搜索引擎的通常索引单位是单词,单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针。倒排列表(PostingList):倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息及频率(作关联性算分),每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。倒排文件(Inverted File):所有单词的倒排列表往往顺序地存储在磁盘的某个文件里,这个文件即被称之为倒排文件,倒排文件是存储倒排索引的物理文件。

以查找搜索引擎查找为例:

图片.png

单词词典查询定位问题

对于一些规模很大的文档集合来讲,他里面可能包括了上百万的关键单词(term),能否快速定位到具体单词(term),这会直接影响到响应速度。 假设我们有很多个 term,比如:

Carla,Sara,Elin,Ada,Patty,Kate,Selena

如果按照这样的顺序排列,找出某个特定的 term 一定很慢,因为 term 没有排序,需要全部过滤一遍才能找出特定的 term。排序之后就变成了:

Ada,Carla,Elin,Kate,Patty,Sara,Selena

这样我们可以用二分查找的方式,比全遍历更快地找出目标的 term。这个就是 term dictionary。有了 term dictionary 之后,可以用 logN 次磁盘查找得到目标。但是磁盘的随机读操作仍然是非常昂贵的(一次 random access 大概需要 10ms 的时间)。所以尽量少的读磁盘,有必要把一些数据缓存到内存里。但是整个 term dictionary 本身又太大了,无法完整地放到内存里。于是就有了 term index。term index 有点像一本字典的大的章节表。

目前常用的方式是通过hash加链表结构和树型结构(b树或者b+)。

hash加链表:

图片.png

这是很常用的一种数据结构。这种方式就可以快速计算单词的hash值从而定位到他所有在的hash表中,如果该表是又是一个链表结构(两个单词的hash值可能会一样),那么就需要遍历这个链表然后再对比返回结果。这种方式最大的缺点就是如果有范围查询的时候就很难做到。

树型结构:

B树(或者B+树)是另外一种高效查找结构,下图是一个 B树结构示意图。B树与哈希方式查找不同,需要字典项能够按照大小排序(数字或者字符序),而哈希方式则无须数据满足此项要求。 B树形成了层级查找结构,中间节点用于指出一定顺序范围的词典项目存储在哪个子树中,起到根据词典项比较大小进行导航的作用,最底层的叶子节点存储单词的地址信息,根据这个地址就可以提取出单词字符串。

安装ES 和 Kibana

一、安装jdk

ElasticSearch是基于lucence开发的,也就是运行需要java jdk支持。所以要先安装JAVA环境。

由于ElasticSearch 5.x 往后依赖于JDK 1.8的,所以现在我们下载JDK 1.8或者更高版本。 下载JDK1.8,下载完成后安装。

二、安装ElasticSearch

1.ElasticSearch下载地址:

https://www.elastic.co/downloads/elasticsearch

2.下载安装包后解压

分布式搜索引擎es 分布式查询引擎_分词器

3.进入bin目录下,双击执行elasticsearch.bat

分布式搜索引擎es 分布式查询引擎_elasticsearch_02

分布式搜索引擎es 分布式查询引擎_分词器_03

4.看到started说明启动成功,打开浏览器测试一下,如下图

访问地址: http://localhost:9200 默认是9200 端口

分布式搜索引擎es 分布式查询引擎_分布式搜索引擎es_04

三、安装Kibana

  1. 在 Windows 中安装 Kibana 使用 .zip 包。

最新稳定版 Kibana 可以从 Kibana 下载页获得。其他版本可以在 已发布版本中查看

分布式搜索引擎es 分布式查询引擎_倒排索引_05

  1. 下载解压文件将解压到下面,会创建一个文件夹叫 kibana-6.6.0-windows-x86_64,也就是我们指的 $KIBANA_HOME 。删除多余的字符,保留如图格式:

分布式搜索引擎es 分布式查询引擎_分词器_06

分布式搜索引擎es 分布式查询引擎_分词器_07

3 . .zip 文件目录

.zip 整个包是独立的。默认情况下,所有的文件和目录都在 $KIBANA_HOME — 解压包时创建的目录下。这是非常方便的,因为您不需要创建任何目录 来使用 Kibana,卸载 Kibana 只需要简单的删除 $KIBANA_HOME目录。但还是建议修改一下配置文件和数据目录,这样就不会删除重要数据。

类型

描述

默认位置

备注

home

Kibana home 目录或 $KIBANA_HOME

解压包时创建的目录

这里就是D:\kibana\6.6.0

bin

二进制脚本,包括 kibana 启动 Kibana 服务和 kibana-plugin 安装插件。

$KIBANA_HOME\bin

config

配置文件包括 kibana.yml

$KIBANA_HOME\config

data

Kibana 和其插件写入磁盘的数据文件位置。

$KIBANA_HOME\data

optimize

编译过的源码。某些管理操作(如,插件安装)导致运行时重新编译源码。

$KIBANA_HOME\optimize

plugins

插件文件位置。每一个插件都一个单独的二级目录。

$KIBANA_HOME\plugins

  1. 通过配置文件配置 KibanaKibana 默认情况下从 $KIBANA_HOME/config/kibana.yml 加载配置文件。该配置文件的格式在 配置 Kibana 中做了说明。在编辑器中打开config / kibana.yml设置elasticsearch.url为指向您的Elasticsearch实例默认值: "http://localhost:9200"** 用来处理所有查询的 Elasticsearch 实例的 URL,所以不用修改。

分布式搜索引擎es 分布式查询引擎_分词器_08

  1. 双击 bin\kibana.bat默认情况下,Kibana将解压在 kibana-6.6.0-windows-x86_64中,这里已经移动到如图所示位置,在此处导航并进入bin目录,如下所示:

分布式搜索引擎es 分布式查询引擎_分词器_09

  1. 使用命令提示符:运行bin/kibana(或bin\kibana.bat在Windows上)默认情况下,Kibana 在前台启动,输出 log 到 STDOUT ,可以通过 Ctrl-C 停止 Kibana。

分布式搜索引擎es 分布式查询引擎_分词器_10

  1. 成功运行节点如果一切顺利安装,你应该看到一堆如下所示的消息:

分布式搜索引擎es 分布式查询引擎_倒排索引_11

  1. 运行

最后一步,就是在浏览器 敲入 http://localhost:5601

分布式搜索引擎es 分布式查询引擎_分词器_12

安装IK 分词器

一、下载

下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases ,这里你需要根据你的Es的版本来下载对应版本的IK

分布式搜索引擎es 分布式查询引擎_倒排索引_13

二、安装

解压-->将文件复制到 ElasticSearch 的安装目录/plugin/ik下面即可,完成之后效果如下:

到这里已经完成了,不需要去elasticSearch的 elasticsearch.yml 文件去配置。

重启ElasticSearch

分布式搜索引擎es 分布式查询引擎_倒排索引_14

三、测试

未使用ik分词器的时候测试分词效果:

POST book/_analyze
{
  "text": "我是中国人"
}
//结果是:
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "是",
      "start_offset": 1,
      "end_offset": 2,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "中",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "国",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 4
    }
  ]
}

使用IK分词器之后,结果如下:

POST book_v6/_analyze
{
  "analyzer": "ik_max_word",
  "text": "我是中国人"
}
//结果如下:
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "是",
      "start_offset": 1,
      "end_offset": 2,
      "type": "CN_CHAR",
      "position": 1
    },
    {
      "token": "中国人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "中国",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 3
    },
    {
      "token": "国人",
      "start_offset": 3,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 4
    }
  ]
}
  1. 如果未安装ik分词器,那么,你如果写 "analyzer": "ik_max_word",那么程序就会报错,因为你没有安装ik分词器
  2. 如果你安装了ik分词器之后,你不指定分词器,不加上 "analyzer": "ik_max_word" 这句话,那么其分词效果跟你没有安装ik分词器是一致的,也是分词成每个汉字

ES的RestFull 语法

RestFull 接口

作用

一些操作方法

GET

查看索引 和 文档信息

GET /index 、GET /index/_doc/1

POST

查询索引信息 和文档信息 ,添加文档数据,修改数据

POST /index/_doc/__search 、POST /index/_doc/1/_update

PUT

创建索引、指定文档的field

PUT /index

DELETE

删除索引和文档信息

DELETE /index 、DELETE /index/_doc/1

ES索引的操作

一、创建索引 PUT

PUT /index
{
    "settings": {
        "number_of_shards": 5,
        "number_of_replicas": 1
  }
}

二、查看索引 GET

GET /index

三、删除索引 DELETE

DELETE /index

ES中常用的Field 类型

一、字符串类型

类型

作用

Text

进行全文检索,会被进行分词处理

KeyWord

不会被进行分词处理

二、数值类型

类型

取值范围

long

-263至263-1

integer

-231至231-1

short

-32,768至32768

byte

-128至127

double

64位双精度IEEE 754浮点类型

float

32位单精度IEEE 754浮点类型

half_float

16位半精度IEEE 754浮点类型

scaled_float

缩放类型的的浮点数(比如价格只需要精确到分,price为57.34的字段缩放因子为100,存起来就是5734)

三、日期类型

类型

作用

Date

日期类型

JSON中没有日期类型,所以在ELasticsearch中,日期类型可以是以下几种:

  1. 日期格式的字符串:e.g. “2015-01-01” or “2015/01/01 12:10:30”.
  2. long类型的毫秒数( milliseconds-since-the-epoch)
  3. integer的秒数(seconds-since-the-epoch)

日期格式可以自定义,如果没有自定义,默认格式如下:

"strict_date_optional_time||epoch_millis"

四、IP类型

ip类型的字段用于存储IPV4或者IPV6的地址。

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "ip_addr": {
          "type": "ip"
        }
      }
    }
  }
}
 
PUT my_index/my_type/1
{
  "ip_addr": "192.168.1.1"
}
 
GET my_index/_search
{
  "query": {
    "term": {
      "ip_addr": "192.168.0.0/16"
    }
  }
}

五、范围类型

range类型支持以下几种:

类型

范围

integer_range

-231至231-1

float_range

32-bit IEEE 754

long_range

-263至263-1

double_range

64-bit IEEE 754

date_range

64位整数,毫秒计时

六、boolean 类型

类型

作用

boolean

true、false

表示 true 、false

七、二进制类型

二进制类型不支持 Base 64位 encode string

八、经纬度查询

类型

作用

geo_point

经纬度查询

ES的一些操作

一、创建索引并指定数据结构

PUT /book
{
  "settings": {
    //分片数
    "number_of_shards": 5,
    //备份属
    "number_of_replicas": 1
  },
    
  "mappings": {
      //指定Field 属性
    "properties": {
        //指定field属性name
      "name":{
        "type": "text",
        //指定分词器
        "analyzer": "ik_max_word",
          //指定当前属性是否可以作为查询条件
        "index": true,
          //是否需要额外存储
        "store": false
      },
      "age":{
        "type":"long"
      },
      "author":{
        "type": "keyword"
      },
      "count":{
        "type": "long"
      },
      "on-sale":{
        "type": "date",
          //设置存放日期类型格式
        "format": "yyyy-MM-dd"
      },
      "desc":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

二、文档的操作

1.添加文档信息

随机生成Id

POST /index/_doc
{
  "name":"张三",
  "age":12
}

指定文档Id

GET /index/_doc/1
{
  "name":"张三",
  "age":12
}

2.更新文档信息

覆盖式更新文档信息

如果没有指定其他属性值,其他属性值也会被修改

PUT /index/_doc/1
{
    "name":"亭亭"
}

doc 方式修改文档信息

POST /index/_doc/1/_update
{
	"_doc":{
		"name":"王五"
	}
}

3.删除文档信息

DELETE 进行删除

DELETE /index/_doc/1

Java连接ES

  1. 创建Maven 工程
  2. 导入依赖
<!--elasticsearch依赖-->
<!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client -->
<!--高级api-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.1</version>
</dependency>
  1. 调用api 连接es
/*
* es 客户端连接 工具类
* */
public class EsClientUtil {

    //ElasticSearch 客户端连接
    public static RestHighLevelClient getEsClient(){

        //http 端口号
        HttpHost httpHost = new HttpHost("127.0.0.1",9200);
        //rest 客户端
        RestClientBuilder builder = RestClient.builder(httpHost);
        //rest 高级Api
        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;
    }

}

使用Java代码操作ES索引

一 创建索引

Settings.builder()

JsonXContent.contentBuilder()

CreateIndexRequest(index)

@Test
public void testCreateEsIndex() throws IOException {
    String index = "person";
    String type = "m";
    //创建settings对象
    Settings.Builder settings = Settings.builder()
            .put("number_of_shards",5)
            .put("number_of_replicas",1);

    //构建mapper 对象
    XContentBuilder mappers = JsonXContent.contentBuilder()
            .startObject()
                .startObject("properties")
                    .startObject("name")
                        .field("type","text")
                    .endObject()
                    .startObject("age")
                        .field("type","long")
                    .endObject()
                    .startObject("birthday")
                        .field("type","date")
                        .field("format","yyyy-MM-dd")
                    .endObject()
                .endObject()
            .endObject();

    //创建索引请求对象
    CreateIndexRequest createIndexRequest = new CreateIndexRequest(index)
            .settings(settings)
            .mapping(mappers);

    //拿到高级ipa发送请求, 创建对象返回结果
    RestHighLevelClient client = test.getRestHighLeveClient();
    CreateIndexResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

    System.out.println(response);
}

二 查询索引是否存在

GetIndexRequest

@Test
public void getIndexEs() throws IOException {

    //创建相对应的reqeust请求
    GetIndexRequest getIndexRequest = new GetIndexRequest(index);
    //使用api 发送请求
    RestHighLevelClient client = test.getRestHighLeveClient();
    GetIndexResponse response = client.indices().get(getIndexRequest, RequestOptions.DEFAULT);
    //输出返回结果
    System.out.println(response);
}

三 删除索引

DeleteIndexRequest

@Test
public void deleteEsIndex()throws IOException {
    //创建delete 请求
    DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest();
    deleteIndexRequest.indices(index);
    //获取client 对象并发送请求
    RestHighLevelClient client = test.getRestHighLeveClient();
    AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest,RequestOptions.DEFAULT);
    System.out.println(delete);

}

使用Java代码操作ES文档

一 添加文档数据

IndexRequest 请求

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.72</version>
</dependency>
public class proson {
    @JSONField(serialize = true)
    private Integer id;
    private Long age;
    private String name;
    @JSONField(format = "yyyy-MM-dd")
    private Date birthday;

    public proson(Integer id, Long age, String name, Date birthday) {
        this.id = id;
        this.age = age;
        this.name = name;
        this.birthday = birthday;
    }

    public proson(Long age, String name, Date birthday) {
        this.age = age;
        this.name = name;
        this.birthday = birthday;
    }

    public Long getAge() {
        return age;
    }

    public void setAge(Long age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
//添加文档
@Test
public void addDoc() throws IOException {
    //数据 转换成json字符串
    proson proson = new proson(1, 2l, "张三", new Date());
    String prosons = JSON.toJSONString(proson);

    //创建indexRequest 对象 指定 索引 , 类型 , Id
    IndexRequest indexRequest = new IndexRequest(index, "_doc", proson.getId().toString());
    //告诉他传入json数据
    indexRequest.source(prosons, XContentType.JSON);  

    //获取对象发送请求
    RestHighLevelClient client = test.getRestHighLeveClient();
    IndexResponse index = client.index(indexRequest, RequestOptions.DEFAULT);
    System.out.println(index);
}

二 修改文档数据

update Request 请求

//修改文档
@Test
public void upDoc() throws IOException {

    //要修改的数据
    Map<String, Object> map = new HashMap<>();
    map.put("name", "无聊");
    //请求
    UpdateRequest updateRequest = new UpdateRequest("person", "_doc", "1");
    updateRequest.doc(map);
    RestHighLevelClient client = test.getRestHighLeveClient();
    client.update(updateRequest, RequestOptions.DEFAULT);
}

三 删除文档数据

Delete Request 请求

@Test
public void deleteText() throws IOException {
    
    //创建删除请求
    DeleteRequest deleteRequest = new DeleteRequest("index","id");
    //发送请求
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    DeleteResponse delete = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
    
}

四 批量添加数据

Bluk Request 请求

//批量添加
@Test
public void addTo() throws IOException {
    //准备添加数据
    proson proson1 = new proson(9, 22l, "大浪", new Date());
    proson proson2 = new proson(3, 25l, "王五", new Date());
    proson proson3 = new proson(4, 13l, "你不行", new Date());

    String s = JSON.toJSONString(proson1);
    String s2 = JSON.toJSONString(proson2);
    String s3 = JSON.toJSONString(proson3);

    //创建bulk请求对象
    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.add(new IndexRequest("person", "_doc", "2").source(s,XContentType.JSON));
    bulkRequest.add(new IndexRequest("person", "_doc", "3").source(s2,XContentType.JSON));
    bulkRequest.add(new IndexRequest("person", "_doc", "4").source(s3,XContentType.JSON));

    //获取EsClient 对象 发送请求
    RestHighLevelClient client = test.getRestHighLeveClient();
    client.bulk(bulkRequest,RequestOptions.DEFAULT);
}

五 批量删除数据

//批量删除
@Test
public void deleteTo() throws IOException {
	//创建多个delete 请求
    DeleteRequest deleteRequest = new DeleteRequest("person","_doc","1");
    DeleteRequest deleteRequest2 = new DeleteRequest("person","_doc","4");
    DeleteRequest deleteRequest3 = new DeleteRequest("person","_doc","2");
	
    //封装进Bulk 请求
    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.add(deleteRequest);
    bulkRequest.add(deleteRequest2);
    bulkRequest.add(deleteRequest3);
    //发送请求
    RestHighLevelClient client = test.getRestHighLeveClient();
    client.bulk(bulkRequest,RequestOptions.DEFAULT);


}

ES 各种查询

重要API:

  1. SearchRequest

2. SearchSourceBuilder

1. term

全文检索,不会对查询关键字进行分词处理

json 格式

POST /sms-logs-index/_search
{
  //从第几条数据开始
  "from":0,
  //显示几条数据
  "size":4,
  "query":{
      //term 查询
    "term":{
        //查询属性 
      "corpName":{
        "value":"安庆"
      }
    }
  }
}

Java 代码

@Test
public void termSearch() throws IOException {

    //创建请求对象
    //------------------------------------------------------------
    SearchRequest searchRequest = new SearchRequest(index);

    //封装查询条件
    //------------------------------------------------------------
    SearchSourceBuilder builder = new SearchSourceBuilder();
    builder.query(QueryBuilders.termQuery("corpName","安庆"));

    //发送请求
    //------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse resp = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取输出结果
    //------------------------------------------------------------
    SearchHit[] hits = resp.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }
}

2. terms

一个字段可以有多个值,相当于数据库中的 where orderName = "1" or orderName = "2"

不会进行分词处理

json 处理

POST /sms-logs-index/_search
{
  "query": {
    "terms": {
      "smsContent": [
        "我",
        "加油"
      ]
    }
  }
}

java代码

@Test
public void termsSearch() throws IOException {

    //创建查询请求
    //-----------------------------------------------------------
    SearchRequest searchRequest = new SearchRequest(index);

    //封装查询条件
    //-----------------------------------------------------------
    SearchSourceBuilder query = new SearchSourceBuilder();
    query.query(QueryBuilders.termsQuery("province","上","北"));
    searchRequest.source(query);

    //发送请求
    //-----------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果
    //-----------------------------------------------------------
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }
}

3. match 查询

match 查询属于高层查询,

会根据字段属性的不同

从而执行不同的查询操作

  1. 如果查询内容是数值类型或其他数据类型如:日期 会进行相对应的类型转换
  2. 如果查询的字段类型可以进行分词处理,那嘛搜索关键字会进行分词处理
  3. 如果查询的字段类型没有进行分词处理,那嘛搜索关键字就不会进行分词处理
POST /sms-logs-index/_search
{
  "query": {
    "match": {
      "smsContent": "我"
    }
  }
}
@Test
public void matchSearch() throws IOException {

    //创建请求
    //--------------------------------------------------------------------------
    SearchRequest request = new SearchRequest(index);

    //构建条件
    //--------------------------------------------------------------------------
    SearchSourceBuilder builders = new SearchSourceBuilder();
    builders.query(QueryBuilders.matchQuery("sendDate","2020-10-23"));
    request.source(builders);
    //发送请求
    //--------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

    //获取响应
    //--------------------------------------------------------------------------
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }
}

4. match all 查询

查询全部内容

POST /sms-logs-index/_search
{
  "query": {
    "match_all": {}
  }
}

Java 代码

//创建请求
    //--------------------------------------------------------------------------
    SearchRequest request = new SearchRequest(index);

    //构建条件
    //--------------------------------------------------------------------------
    SearchSourceBuilder builders = new SearchSourceBuilder();
    builders.query(QueryBuilders.matchAllQuery());
    request.source(builders);

    //发送请求
    //--------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

    //获取响应
    //--------------------------------------------------------------------------
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }
}

5. match bool 查询

可以用来进行 and 或者 or 进行条件查询

POST /sms-logs-index/_search
{
  "query":{
    "match": {
        "province":{
          "query": "北 河",
          "operator":"or"
        }
    }
  }
}
@Test
public void booleanMatchSearch() throws IOException {

    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchQuery("province","上海 河南").operator(Operator.OR));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

}

6. multi_match 查询

多个字段对一个值进行查询

POST /sms-logs-index/_search
{
  "query": {
    "multi_match": {
      "query": "我",
      "fields": ["province","smsContent","corpName"]
    }
  }
}
@Test
public void multiMatchSearch() throws IOException {
    //创建请求
    //--------------------------------------------------------------------------
    SearchRequest request = new SearchRequest(index);

    //构建条件
    //--------------------------------------------------------------------------
    SearchSourceBuilder builders = new SearchSourceBuilder();
    builders.query(QueryBuilders.multiMatchQuery("上","smsContent","province"));
    request.source(builders);

    //发送请求
    //--------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

    //获取响应
    //--------------------------------------------------------------------------
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }
}

7. Id 查询

根据id 进行查询

可以根据get 进行查询

GET /index/_doc/1
@Test
public void getIdSearch() throws IOException {
    //创建请求
    //GetIndexRequest getIndexRequest = new GetIndexRequest(index,"_doc","1");
    GetRequest request = new GetRequest(index,"1");

    //发送请求
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    GetResponse response = esClient.get(request, RequestOptions.DEFAULT);

    //输出结果
    System.out.println(response.getSourceAsMap());
}

8. Ids 查询

根据多个id 进行查询,类似与 Mysql中 where id in ("1","2","3")

POST /sms-logs-index/_search
{
  "query": {
    "ids": {
      "values": [1,2,3]
    }
  }
}
@Test
public void idsSearch() throws IOException {

    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.idsQuery().addIds("1","2","3","4"));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

}

9. prefix 查询

前缀查询

POST /sms-logs-index/_search
{
  "query": {
    "prefix": {
      "corpName": {
        "value": "安庆"
      }
    }
  }
}
@Test
public void prefixSearch() throws IOException {


    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.prefixQuery("province","上"));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }


}

10. fuzzy 查询

模糊查询

可以根据length 指定长度进行查询

POST /sms-logs-index/_search
{
  "query": {
    "fuzzy": {
      "corpName": {
        "value": "安庆",
        "prefix_length": 2
      }
      
    }
  }
}
@Test
public void fuzzySearch() throws IOException {

    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.fuzzyQuery("province","河"));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

}

11. wildcard 查询

可以使用通配符进行查询

通配符 * , ?

POST /sms-logs-index/_search
{
  "query": {
    "wildcard": {
      "corpName": {
        "value": "安*"
      }
    }
  }
}
@Test
public void wildcardSearch() throws IOException {

    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.wildcardQuery("province","上*"));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

}

12. range 查询

范围查询 只能进行数值类型

POST /sms-logs-index/_search
{
  "query": {
    "range": {
      "operatorld": {
        "gte": 0,
        "lte": 3            //gt > || gte >=  || lt < || lte<=
      }
    }
  }  
}
@Test
public void rangeSearch() throws IOException {

    //创建请求
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    //-------------------------------------------------------------------------------
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.rangeQuery("replyTotal").lte(30).gte(10));
    searchRequest.source(searchSourceBuilder);

    //发送请求
    //-------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse search = esClient.search(searchRequest, RequestOptions.DEFAULT);

    //获取结果进行输出
    //-------------------------------------------------------------------------------
    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

}

13. regexp 查询

正则查询

14. Scroll 查询

深分页查询

查询数据原理:

  1. es会将用户搜索关键字进行分词处理
  2. 根据分词结果到分词库中查询数据拿到文档id
  3. 会将文档id 保存进上下文中
  4. 根据size 依次从上下文中获取文档id 拿到数据
  5. 不建议实时查询信息
#深分页
POST /sms-logs-index/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 2
}
POST /_search/scroll
 {
   "scroll_id":"DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAF1pFlBIeUhfR1FwUWNHWHluMURXN3FwdWcAAAAAAABdahZQSHlIX0dRcFFjR1h5bjFEVzdxcHVnAAAAAAAAXWsWUEh5SF9HUXBRY0dYeW4xRFc3cXB1Zw==",
   "scroll":"1m"
 }

删除scroll

DELETE /_search/scroll/DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAF1pFlBIeUhfR1FwUWNHWHluMURXN3FwdWcAAAAAAABdahZQSHlIX0dRcFFjR1h5bjFEVzdxcHVnAAAAAAAAXWsWUEh5SF9HUXBRY0dYeW4xRFc3cXB1Zw==
@Test
public  void scrollSearch() throws IOException {
    //创建请求
    //----------------------------------------------------------------------------
    SearchRequest request = new SearchRequest(index);

    //指定scroll信息
    //----------------------------------------------------------------------------
    request.scroll(TimeValue.timeValueMillis(1l));

    //指定查询条件
    //----------------------------------------------------------------------------
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.size(2);
    sourceBuilder.query(QueryBuilders.matchAllQuery());

    request.source(sourceBuilder);

    //获取es 客户端 并发送请求
    //----------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

    //获取scroll Id
    //----------------------------------------------------------------------------
    String scrollId = response.getScrollId();
    System.out.println(scrollId);

    //输出打印结果
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getSourceAsMap());
    }

    //循环进行下一页 操作 没有数据就退出循环
    //----------------------------------------------------------------------------
    while (true){
        //创建Scroll 查询请求
        SearchScrollRequest searchScrollRequest = new SearchScrollRequest();

        //设置要查询的scroll Id
        searchScrollRequest.scrollId(scrollId);
        searchScrollRequest.scroll(TimeValue.timeValueMillis(1l));

        //使用客户端发送请求
        SearchResponse resp = esClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
        //判断是否有数据
        if(resp.getHits().getHits().length > 0){
            SearchHit[] searchHits = resp.getHits().getHits();
            for (SearchHit searchHit : searchHits) {
                System.out.println(searchHit.getSourceAsMap());
            }
        }else {
            break;
        }

    }

    //删除Scroll
    //-----------------------------------------------------------------
    ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
    clearScrollRequest.addScrollId(scrollId);
    esClient.clearScroll(clearScrollRequest,RequestOptions.DEFAULT);

    System.out.println("删除成功");


}

15 delete by query

将查询到的数据进行删除操作

/**
 * delete by query
 * */
@Test
public void deleteByQuery() throws IOException {
    //创建delete by query 查询
    //----------------------------------------------------------------------------------------------
    DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);

    //构建条件
    //----------------------------------------------------------------------------------------------
    deleteByQueryRequest.setQuery(QueryBuilders.matchQuery("corpName","安庆景博信息科技"));

    //发送请求
    //----------------------------------------------------------------------------------------------
    RestHighLevelClient esClient = EsClientUtil.getEsClient();
    BulkByScrollResponse response = esClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
    System.out.println(response);
}

16 高亮查询

POST /sms-logs-index/_search
{
  "query": {
    "match": {
      "corpName": "安庆科技"
    }
  },
  "highlight": {
    "fields": {
      "corpName": {}
    },
    "pre_tags": "<font class='red'>",
    "post_tags": "<font/>",
    "fragment_size":3
  }
}
/**
 * 高亮查询
 * */
@Test
public void highlightSearch() throws IOException {

    //创建请求
    SearchRequest request = new SearchRequest(index);

    //设置条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.matchQuery("corpName","安庆科技"));

    //构建highlight 条件
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field("corpName",3).preTags("<font class='red'>").postTags("<font/>");

    //封装  highlightBuilder
    sourceBuilder.highlighter(highlightBuilder);
    //封装  sourceBuilder
    request.source(sourceBuilder);

    //发送请求
    SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);

    //获取返回结果进行处理
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
        System.out.println(hit.getHighlightFields());
    }

}

17 cardinality 聚合查询

将文档中重复数据进行去重处理

POST /sms-logs-index/_search
{
  "aggs": {
    "agg": {
      "cardinality": {
        "field": "state"
      }
    }
  }
}

.aggregation()

AggregationBuilders

Cardinality

/**
 * 聚合查询
 * cardinality 重计项
 * */
@Test
public void cardinalitySearch() throws IOException {

    //创建查询
    SearchRequest searchRequest = new SearchRequest(index);

    //封装条件
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.aggregation( AggregationBuilders.cardinality("agg").field("state"));

    searchRequest.source(searchSourceBuilder);
    //发送请求
    SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT);
    //返回结果 输出
    Cardinality agg = response.getAggregations().get("agg");

    System.out.println(agg.getValue());
}

18 range 聚合查询

range : 一般数值类型查询

ip_range: 根据ip 查询

date_range: 根据日期进行查询

range聚合

{
    "aggs": {
      "agg_range": {
        "range": {
          "field": "cost",
          "ranges": [
            {
              "from": 50,
              "to": 70
            },
            {
              "from": 100
            }
          ]
        },
        "aggs": {
          "bmax": {
            "max": {
              "field": "cost"
            }
          }
        }
      }
    }
}

date_range聚合

POST /sms-logs-index/_search
{
  "aggs": {
    "agg": {
      "date_range": {
        "field": "createDate",
        "format": "yyyy", 
        "ranges": [
          {
            "from": "2020",
            "to": "2021"
          }
        ]
      }
    }
  }
}

ip_range聚合

POST /sms-logs-index/_search
{
  "aggs": {
    "agg": {
      "ip_range": {
        "field": "corpName",
        "ranges": [
          {
            "from": "10.0.0.5",
            "to": "10.0.0.10"
          }
        ]
      }
    }
  }
}

19 extendedStats 查询

可以查询出一个字段的 最大值 , 最小值, 平均值 等...非常好用

POST /sms-logs-index/_search
{
  "aggs": {
    "agg": {
      "extended_stats": {
        "field": "operatorld"
      }
    }
  }
}

20. 经纬度查询

21. 复合查询

23. filter查询