ElasticSearch学习


官方文档

中文文档

基本概念

文章

上面这篇文章可以对其有个很好的理解

1、Index

索引这个词在 ElasticSearch 会有三种意思:

1)、索引(名词)

类比传统的关系型数据库领域来说,索引相当于SQL中的一个数据库(Database)。索引由其名称(必须为全小写字符)进行标识。(现在看来更相当于数据库的Table)

2)、索引(动词)

保存一个文档到索引(名词)的过程。这非常类似于SQL语句中的 INSERT关键词。如果该文档已存在时那就相当于数据库的UPDATE。

3)、倒排索引

关系型数据库通过增加一个B+树索引到指定的列上,以便提升数据检索速度。索引ElasticSearch 使用了一个叫做 倒排索引 的结构来达到相同的目的。

2、Type(弃用)

一个Index下支持多个Type–有点类似于消息队列一个topic下多个group的概念

Type 可以理解成关系数据库中Table。

之前的版本中,索引和文档中间还有个类型的概念,每个索引下可以建立多个类型,文档存储时需要指定index和type。

从6.0.0开始单个索引中只能有一个类型,7.0.0以后将将不建议使用,8.0.0 以后完全不支持。

弃用该概念的原因:

我们虽然可以通俗的去理解Index比作 SQL 的 Database,Type比作SQL的Table。但这并不准确,因为如果在SQL中,Table 之前相互独立,同名的字段在两个表中毫无关系。但是在ES中,同一个Index 下不同的 Type 如果有同名的字段,他们会被 Luecence当作同一个字段,并且他们的定义必须相同。

而Type字段并没有多少意义。目前Type已经被Deprecated,在7.0开始,一个索引只能建一个Type为_doc

去除type就是为了提高es的效率

3、Document

Document 等同于关系型数据库表中的行。(Document相当于数据库的一行记录)

_index 文档所属索引名称。

_type 文档所属类型名。

_id Doc的主键。在写入的时候,可以指定该Doc的ID值,如果不指定,则系统自动生成一个唯一的UUID值。

_version 文档的版本信息。Elasticsearch通过使用version来保证对文档的变更能以正确的顺序执行,避免乱序造成的数据丢失。

_seq_no 严格递增的顺序号,每个文档一个,Shard级别严格递增,保证后写入的Doc的_seq_no大于先写入的Doc的_seq_no。

primary_term primary_term也和_seq_no一样是一个整数,每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1

found 查询的ID正确那么ture, 如果 Id 不正确,就查不到数据,found字段就是false。

_source 文档的原始JSON数据。

4、其他
  • Field:相当于数据库的Column (属性就是列名)
  • Mapping:相当于数据库的Schema( schema是元数据的一个抽象集合,包含一套schema component: 主要是元素与属性的声明、复杂与简单数据类型的定义 )
  • DSL:相当于数据库的SQL(给我们读取Elasticsearch数据的API)

Docker中安装

下载(全部)

docker pull elasticsearch:[版本] 存储和检索数据
docker pull kibana:[版本] 可视化检索数据
# 版本要一致

配置(elasticsearch)

# 将docker里的目录挂载到linux的/mydata目录中
# 修改/mydata就可以改掉docker里的
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data

# es可以被远程任何机器访问
echo "http.host: 0.0.0.0" >/mydata/elasticsearch/config/elasticsearch.yml

# 递归更改权限,es需要访问(不建议)
chmod -R 777 /mydata/elasticsearch/

启动(elasticsearch)

# 9200是用户交互端口 9300是集群心跳端口
# -e指定是单阶段运行
# -e指定占用的内存大小,生产时可以设置32G
# -v来挂载,修改前者就是修改后者,装插件不用进容器内部了
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e  "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v  /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2 


# 设置开机启动elasticsearch
docker update elasticsearch --restart=always

权限

如何想要修改文件,结果没有权限;怎么办呢?

# r (读) = 4
# w (写) = 2
# x (可执行) = 1
# 无权限 = 0 特定用户类的权限数字是该类的权限值之和。

# setuid = 4
# setgid = 2
# sticky = 1
# no changes = 0 接下来的三位数的含义与使用三位数时相同。
chmod -R 777 #使用这个可以让你拥有所有全县(4+2+1 = 7)(但是并不建议使用该命令)

文件或目录设置777权限意味着它将对所有用户都是可读、可写和可执行的,并且可能会带来巨大的安全风险。

例如,如果你以递归方式将 /var/www 目录下所有文件和子目录的权限更改为777,则系统上的任何用户都可以创建、删除或修改该目录中的文件。

如果你的Web服务器遇到权限问题,请将文件的所有权更改为运行应用程序的用户,并将文件的权限设置为644,将目录的权限设置为755,而不是递归地将权限设置为777。

可以使用chown命令更改文件所有权,使用chmod命令更改权限。

假设您的服务器上有一个应用程序以用户“www”身份运行。

要设置要运行的正确权限,请执行以下操作:

chown -R www: /var/www
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;

只有root用户、文件所有者或具有sudo权限的用户才能更改文件的权限。

使用chmod时要格外小心,特别是在递归更改权限的时候。

启动(kibana)

# kibana指定了了ES交互端口9200  # 5600位kibana主页端口
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 -d kibana:7.4.2


# 设置开机启动kibana
docker update kibana  --restart=always

测试

http://192.168.56.10:9200 #浏览器或者请求连接的工具打开,查看版本信息

初步使用

ES里面存的都是json文档

1、基本信息查看

都是主机地址加/_cat……

  1. GET /_cat/nodes:查看所有节点 (*代表主节点)
  2. GET /_cat/health:查看es健康状况
  3. GET /_cat/master:查看主节点
  4. GET/_cat/indicies:查看所有索引 ,等价于mysql数据库的show databases;
2、新增
# PUT新增
# # 在customer索引下的external类型下保存1号数据
PUT customer/external/1

# POSTMAN输入
http://192.168.56.10:9200/customer/external/1

# 同时在请求体中加入json数据就行了

PUT和POST区别

  1. POST不指定id,一直发送请求,会一直(指定不存在的id)新增(自动生成唯一标识id)。指定id后,继续以这个id发送请求,就是(指定存在的id)更新操作了,会迭代(根据内容变化)版本号
  2. PUT可以新增也可以修改,但是必须指定id,版本号也会一直迭代

所有的请求成功后,会返回

返回数据:
带有下划线开头的,称为元数据,反映了当前的基本信息。  
{
    "_index": "customer", 表明该数据在哪个数据库下;
    "_type": "external", 表明该数据在哪个类型下;
    "_id": "1",  表明被保存数据的id;
    "_version": 1,  被保存数据的版本
    "result": "created", 这里是创建了一条数据,如果重新put一条数据,则该状态会变为updated,并且版本号也会发生变化。
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
3、查询

使用GET /customer/external/1或者http://192.168.56.10:9200/customer/external/1发送请求,然后返回:

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 1,
    "_seq_no": 1,//并发控制字段,每次更新都会+1,用来做乐观锁
    "_primary_term": 1,//同上,主分片重新分配,如重启,就会变化
    "found": true,
    "_source": {
        "name": "John Doe"
    }
}

更新

就是当两个人并发操作这一个name(_source中的)时,前一个人操作后(请求链接后加if_seq_no=1&if_primary_term=1),这个_seq_no每次更新操作后都会改变,后一个人再按原来的操作(需要最新的这个值)就会报错error(类似乐观锁,需要有if_seq_no=1&if_primary_term=1才会出现这种情况)

4、更新
# 使用_update,需要用"doc";不然会出现解析异常
POST customer/externel/1/_update
{
    "doc":{
        "name":"111"
    }
}
或者
POST customer/externel/1
{
        "name":"222"
}
或者
PUT customer/externel/1
{
        "name":"222"
}
  1. POST带_update,更新的时候会对比数据是否改变,没有变化则不会改变版本号等
  2. POST不带_update以及PUT操作每次更新都会改变版本号

对于大并发更新,不带update

对于大并发查询偶尔更新,带update;对比更新,重新计算分配规则

5、删除
DELETE customer/external/1
DELETE customer
  • elasticsearch并没有提供删除类型的操作,只提供了删除索引和文档的操作 (type现在弃用了)

  • 重复删除会找不到,删除后也查询不到

  • 删除索引后,查询所有索引就查不到了

6、bulk批量API

POST 主机地址//customer/external/_bulk

#两行为一个整体
{"index":{"_id":"1"}}
{"name":"a"}
{"index":{"_id":"2"}}
{"name":"b"}
#注意格式json和text均不可,要去kibana里Dev Tools

#格式
{action:{metadata}}\n
{request body  }\n

{action:{metadata}}\n
{request body  }\n
  • 某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的
  • 当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了

在kibana里Dev Tools的例子

POST /customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"John Doe"}

整个ES执行批量操作

POST /_bulk
{"delete":{"_index":"website","_type":"blog","_id":"123"}}
{"create":{"_index":"website","_type":"blog","_id":"123"}}
{"title":"my first blog post"}
{"index":{"_index":"website","_type":"blog"}}
{"title":"my second blog post"}
{"update":{"_index":"website","_type":"blog","_id":"123"}}
{"doc":{"title":"my updated blog post"}}
7、批量导入数据

准备一份文档样本,每一个都有下列的schema(模式)。可以理解为一种规范。

{
	"account_number": 1,
	"balance": 39225,
	"firstname": "Amber",
	"lastname": "Duke",
	"age": 32,
	"gender": "M",
	"address": "880 Holmes Lane",
	"employer": "Pyrami",
	"email": "amberduke@pyrami.com",
	"city": "Brogan",
	"state": "IL"
}

测试
导入测试数据 (也可以在其他地方找到测试数据)

最后执行:

POST bank/account/_bulk # 必须指定索引 (就是数据库==类比)
上面的数据

进一步检索

1、查询

两种方式:

  • 通过REST request uri 发送搜索参数 (uri +检索参数)
  • 通过REST request body 来发送它们(uri+请求体)

API

#第一种
GET ……/_search?q=*&sort=account_number:asc

#第二种
GET ……/_search
{
  "query": { "match_all": {} }, # 查询条件:全部
  "sort": [ # 排序条件
    { "account_number": "asc" }, # 某个字段的某种顺序
    { "balance":"desc"}
  ]
}
2、复杂查询

Elasticsearch提供了一个可以执行查询的Json风格的DSL(domain-specific language领域特定语言) 。(可以类比sql)

格式

# 查询时,除了query、sort还有许多其他条件
GE1T ……/_search
{
  QUERY_NAME:{   # 使用的功能
     FIELD_NAME:{  #  功能参数
       ARGUMENT:VALUE,
       ARGUMENT:VALUE,...
      }   
   }
}

# "from": 0   从第几条文档开始查
# "size": 0   查询几条数据
# "_source":["……"]   查询指定字段

条件查询,类似where、like等等

  • match适用于全文检索;字符串等;文本字段
  • term适用于精确检索;比如数字(年龄多少等等);非文本字段
#"query": {
#    "match": {
#      "……": "……"  某个字段匹配某个值
#    }
#  }

# 字符串检索是全文检索,会分词查询
"query": {
    "match": {
      "address": "kings"
    }
  }

# match_phrase就是不分词查询
# 短语匹配
"query": {
    "match_phrase": {
      "address": "mill road" 
    }
  }

# 不分词且完全匹配
# 使用keyword,匹配的条件就是要显示字段的全部值,要进行精确匹配的
"query": {
    "match_phrase": {
      "address.keyword": "990 Mill"
    }
  }

# multi_match指定多个字段匹配query,带分词
"query": {
    "multi_match": {
      "query": "mill",
      "fields": [ # state和address有mill子串  谁有都可以
        "state",
        "address"
      ]
    }
  }


# bool复合查询
"query":{
        "bool":{  # 
             "must":[ # 必须有这些字段 (匹配了得分,相关性得分)
              {"match":{"address":"mill"}},
              {"match":{"gender":"M"}}
             ],
			"must_not": [], #必须不匹配
			"should": [] #可以匹配,但不匹配也没关系;匹配了会是个加分项(相关性得分)
			"filter": {  # query.bool.filter
        		"range": { # 区间
          			"balance": {  # 哪个字段
            			"gte": "10000", # 大于
            			"lte": "20000" # 小于
                  	}
        		}
      		}
         }
    }

# term查询非文本,主要是精确字段
"query": {
    "term": {
      "age": "111"
    }
  }

bool查询中,must, shouldmust_not 元素都被称为查询子句 。 文档是否符合每个“must”或“should”子句中的标准,决定了文档的“相关性得分”。 得分越高,文档越符合您的搜索条件。 默认情况下,Elasticsearch返回根据这些相关性得分排序的文档。 must_not 子句中的条件被视为过滤器。它影响文档是否包含在结果中,但不影响文档的评分方式。 相关性得分即是_score

aggregations 执行聚合

可以类比数据库中的group还有聚合函数

#格式
"aggs":{ # 聚合
    "aggs_name":{ # 这次聚合的名字,方便展示在结果集中
        # terms:看值的可能性分布,会合并锁查字段,给出计数即可
        # avg:看值的分布平均
        "AGG_TYPE":{} # 聚合的类型(avg,term,terms)
     }
}

# 例如
"aggs":{ # 聚合
    "ageAgg": {  # 聚合的名字,随便起
      "terms": { # 看值的可能性分布,大概会返回这个age的所有种类及当前种类的个数等
        "field": "age",
        "size": 10
      }
    },
    "ageAvg": { 
      "avg": { # 看age值的平均
        "field": "age"
      }
    }
}

#当然,聚合下可以嵌套聚合,即子聚合;即按照要求分组后的数据,再按要求求出聚合结果
"aggs": {
    "ageAgg": {
      "terms": { # 看分布
        "field": "age",
        "size": 100
      },
      "aggs": { # 与terms并列
        "ageAvg": { #平均
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
# 自然还有很多复杂情况

Mapping字段映射

1、字段类型

核心数据类型

  1. 字符串
    1. text ⽤于全⽂索引,搜索时会自动使用分词器进⾏分词再匹配
    2. keyword 不分词,搜索时需要匹配完整的值
  2. 数值
    1. 整型: byte,short,integer,long
    2. 浮点型: float, half_float, scaled_float,double
  3. 日期: date
  4. 范围
    1. integer_range, long_range, float_range,double_range,date_range
    2. gt,lt,e
  5. 布尔:boolean
  6. 二进制:binary 会把值当做经过 base64 编码的字符串,默认不存储,且不可搜索

复杂数据类型

  1. 对象:object 一个对象中可以嵌套对象
  2. 数组:Array

嵌套类型

  • nested 用于json对象数组
2、查看mapping信息

(可以类比数据库中表的所有字段的类型)

GET ……/_mapping
3、创建映射
PUT /my_index # 创建索引 (类比数据库)
{
  "mappings": {
    "properties": { # 给字段加类型
      "age": {
        "type": "integer"
      },
      "email": {
        "type": "keyword" # 指定为keyword
      },
      "name": {
        "type": "text" # 全文检索。保存时候分词,检索时候进行分词匹配
      }
    }
  }
}
4、给已有索引添加新的映射

不可以使用创建映射的方法添加

PUT /my_index/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false # 字段不能被检索,默认为true
    }
  }
}
5、更新映射(数据迁移)

对于已经存在的字段映射,我们不能更新。因为已有的字段数据,在更新之后可能会失效。 更新必须创建新的索引,进行数据迁移。

数据迁移

首先要创建新的索引,并且指定映射

# 没有类型时的迁移
POST _reindex
{
  "source":{
      "index":"twitter" #旧索引
   },
  "dest":{
      "index":"new_twitters" #新索引
   }
}

#有类型时的迁移
POST _reindex
{
  "source":{
      "index":"twitter",
      "type":"twitter" #类型
   },
  "dest":{
      "index":"new_twitters"
   }
}

分词

1、标准分词器

一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens词元,通常是独立的单词),然后输出tokens流。

elasticsearch提供了很多内置的分词器(标准分词器),可以用来构建custom analyzers(自定义分词器)。

POST _analyze
{
  "analyzer": "standard", # ES自带标准分词器
  "text": "The 2 Brown-Foxes bone."
}
# 结果就是这句话按照空格分词

一般标准分词器都是支持英文的

2、中文分词器(ik分词器)

所有的语言分词,默认使用的都是“Standard Analyzer”,但是这些分词器针对于中文的分词,并不友好。为此需要安装中文的分词器。

  • 安装插件后有些服务没法用了,可能时内存不够,需要分配。

第一种

如果在docker中安装elasticsearch时,把配置文件 /elasticsearch/plugins 映射到服务器主机中了,就可以在该主机的该目录下下载 elasticsearch-analysis-ik-7.x.x.zip 文件,然后解压,重启ES。

第二种

自然就是去容器内部安装了

curl http://主机ip:端口可以查看正在使用该端口的程序的信息,如ES

  1. 进入docker的ES容器的plugin目录下

    # docker exec -it 容器id /bin/bash (要是管理员才可以)
    docker exec -it elasticsearch /bin/bash
    
    pwd # 看看是不是已经进入容器内了
    
    # 如果没有wget,安装就是了yum install wget等等
    wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.x.x/elasticsearch-analysis-ik-7.x.x.zip
    
    # 解压
    unzip elasticsearch-analysis-ik-7.x.x.zip -d ik
    # 要保证ik被移动到了plugins
    mv ik plugins/
    # 权限也要适当赋予
    # 重启服务
    docker restart elasticsearch
    
    # 删除安装包(方法可以网上搜索)
    rm -rf elasticsearch-analysis-ik-7.x.x.zip
    
  2. 测试安装是否完成

    # 默认分词器
    GET _analyze
    {
       # "analyzer": "standard", 
       "text":"我在学习ES"
    }
    
    # ik智能分词
    GET _analyze
    {
       "analyzer": "ik_smart", 
       "text":"我在学习ES"
    }
    
    # 最大的单词组合
    GET _analyze
    {
       "analyzer": "ik_max_word", 
       "text":"我在学习ES"
    }
    # 等等等,输出的分词效果都有所不同
    
3、自定义词库

两种方式:

  1. 实现一个服务,专门用来处理ik分词器的请求,让ik分词器给该项目发送请求。
  2. 使用nginx服务器,在nginx上维护扩展词库,然后ik分词器远程向nginx发送请求,获取新的单词。

nginx方式

# docker中安装并启动nginx
docker run -p 80:80 --name nginx -d nginx:1.10

# 查看是否启动
docker ps

#在相关目录下创建nginx文件夹用来映射nginx的配置文件,进入其中复制喽
mkdir nginx
docker container cp nginx:/etc/nginx .

#修改nginx文件夹下copy的nginx文件夹名字为conf,代表是nginx的配置文件夹
#会挂载这个文件夹和容器的配置文件映射
mv nginx conf


#停掉之前的nginx容器并删除
docker stop ${容器id} //停止容器
docker rm ${容器id} //删除容器

#之前的操作,因为是在docker中下载的,所以服务器中并没有nginx的配置,所以挂载没法对应;需要copy然后重新挂载
#重新创建一个nginx容器,加上要挂载的目录
docker run -p 80:80 --name nginx \
-v /目录/nginx/html:/usr/share/nginx/html \ 
-v /目录/nginx/logs:/var/log/nginx \
-v /目录/nginx/conf:/etc/nginx \
-d nginx:1.10

#启动成功后,服务器中的nginx文件夹下会多出两个文件夹,如上 -v后的
#在html文件夹下一个es文件夹,然后再该文件夹下再新建一个fenci.txt文件作为词库,这个就是ik分词器远程获取新单词的源头文件,编辑该文件;在其中加入新词语
mkdir es
cd es
vim fenci.txt

#为ik分词器配置远程词源的地址,也就是fenci.txt的地址
#进入/elasticsearch/plugins/ik/config目录中,会发现有个IKAnalyzer.cfg.xml文件
vim IKAnalyzer.cfg.xml

#然后配置远程扩展字典
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict"></entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords"></entry>
	<!--用户可以在这里配置远程扩展字典 -->
	<entry key="remote_ext_dict">http://192.168.56.10/es/fenci.txt</entry> 
	<!--用户可以在这里配置远程扩展停止词字典-->
	<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

#最后,重启ES容器,就可以了

SpringBoot集成ES

这些东西可以看官方文档,一般最新的好用

java操作es有两种:

  1. 9300:TCP 弃用啦
  2. 9200:HTTP
    • jestClient 、 RestTemplate 、 HttpClient 都是,但不用
    • Elasticsearch-Rest-Client : 官方RestClient ,使用
1、导入依赖
<!-- Elasticsearch-Rest-Client -->
<!-- 版本号与ELK版本匹配 -->
<!-- ELK即Elasticsearch、Logstash、Kibana -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.4.2</version>
</dependency>

<!-- 如果springboot自动依赖了ES,且版本不一致,需要我们修改 -->
<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.4.2</elasticsearch.version>
</properties>
2、创建配置类
@Configuration
public class ElasticSearchConfig {
    
    public static final RequestOptions COMMON_OPTIONS;

    static {
        //es添加了安全访问规则,访问es需要添加一个安全头,就可以通过requestOptions设置
        //官方建议把requestOptions创建成单实例
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();

        //这中间可能还有一些设置项,就是添加安全头之类的
        
        COMMON_OPTIONS = builder.build();
    }
    
    @Bean
    public RestHighLevelClient esRestClient() {

        RestClientBuilder builder = null;
        // 可以指定多个es
        builder = RestClient.builder(new HttpHost(host, 9200, "http"));

        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;
    }
}
3、保存数据
@Test
public void indexData() throws IOException {
    
    // 设置索引
    IndexRequest indexRequest = new IndexRequest ("users");
    indexRequest.id("1");

    User user = new User();//保存方式有多,建议使用实体类
    //user.setUserName("张三");
    //user.setAge(20);
    //user.setGender("男");
    String jsonString = JSON.toJSONString(user);//转为json数据
    
    //传入要保存的内容,指定数据类型
    indexRequest.source(jsonString, XContentType.JSON);
    
    //执行创建索引和保存数据
    //如果保存的id存在,不会报错,会使版本号增大
    IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);

    System.out.println(index);
}
4、检索数据

官方文档——检索

 @Test
    public void find() throws IOException {
        // 1 创建检索请求
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("bank");//查询哪个索引
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 构造检索条件
        //sourceBuilder.query(); 等等直接用es检索时候的字段,都可以找到方法
        sourceBuilder.query(QueryBuilders.matchQuery("address","mill"));//QueryBuilders工具类
        //AggregationBuilders工具类构建AggregationBuilder
        // 构建第一个聚合条件:按照年龄的值分布
        TermsAggregationBuilder agg1 = AggregationBuilders.terms("agg1").field("age").size(10);// 聚合名称terms

        sourceBuilder.aggregation(agg1);
        // 构建第二个聚合条件:平均薪资
        AvgAggregationBuilder agg2 = AggregationBuilders.avg("agg2").field("balance");
        sourceBuilder.aggregation(agg2);

        //System.out.println("检索条件"+sourceBuilder.toString());

        searchRequest.source(sourceBuilder);//请求中放入检索条件

        // 2 执行检索
        SearchResponse response = client.search(searchRequest, GuliESConfig.COMMON_OPTIONS);//放入检索请求和规定,获得结果
        // 3 分析响应结果
        System.out.println(response.toString());
        
        //获取响应结果的Buckets分析
        Aggregations aggregations = response.getAggregations();
		Terms agg21 = aggregations.get("agg2");
		for (Terms.Bucket bucket : agg21.getBuckets()) {
    		String keyAsString = bucket.getKeyAsString();
    		System.out.println(keyAsString);
		}
    }

响应结果转化为实体类bean

SearchHits hits = response.getHits();//获取最外层hits
SearchHit[] hits1 = hits.getHits();//获取内层hits
//如果是自己想要的那一层就遍历
for (SearchHit hit : hits1) {
    //hit.getId();
    //hit.getIndex();
    String sourceAsString = hit.getSourceAsString();//获得数据json格式,即字符串格式
    Account account = JSON.parseObject(sourceAsString, Account.class);//转为实体类
    System.out.println(account);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值