Elasticsearch的使用

一、引言

**全文检索应用场景:**例如:京东、淘宝、主题搜索等应用。

  1. 搜索的数据对象是大量的非结构化的文本数据。
  2. 文件记录量达到数十万或数百万个甚至更多。
  3. 支持大量基于交互式文本的查询。
  4. 需求非常灵活的全文搜索查询。
  5. 对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
  6. 对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。

1.1 海量数据

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

1.2 全文检索

在应对海量数据进行全文检索功能时,如果使用数据库,效率太低。

1.3 高亮显示

将搜索关键字,以红色的字体展示。

1.4全文检索

百度百科中的定义
全文搜索引擎是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

1.5为什么要用全文搜索搜索引擎

常规的方式:所有数据在数据库里面都有,而且 Oracle、SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询获得,如果查询效率低下,还可以通过建数据库索引,优化SQL等方式进行提升效率,甚至通过引入缓存来加快数据的返回速度。如果数据量更大,还可以分库分表来分担查询压力。

  • 数据类型
    全文索引搜索支持非结构化数据的搜索,可以更好地快速搜索大量存在的任何单词或单词组的非结构化文本。
    例如 Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。
  • 索引的维护
    一般传统数据库,相比进行全文检索查询时的性能变的很慢,进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。

**目前主流的搜索引擎大概就是:**Lucene,Solr,ElasticSearch。

二、ES概述


2.1 ES的介绍

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

  • Lucene:Lucene本身就是一个搜索引擎的底层。

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

  • 全文检索:将一段词语进行分词,并且将分出的单个词语统一的放到一个分词库中,在搜索时,根据关键字去分词库中检索,找到匹配的内容。(倒排索引)

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

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

2.2 倒排索引

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

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

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

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

三、ES的结构

​ 在使用真正使用ES之前,我们首先需要熟悉ES是用怎样的结构与层级关系来存放数据的。

3.1 索引Index,分片和备份——>类比于数据库中的库

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

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

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

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

  • 备份的分片必须放在不同的服务器中。

索引分片备份
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UY10Cdrn-1615968962507








)(es文档图片\1587048753470.png)] |

3.2 类型 Type——>类比于数据库中的表

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

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

类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FL0Z1SPJ-1615968962509)(es文档图片\1587048924







494.png)] |

PS:(特别注意!!!)

ElasticSearch7-去掉type概念

Elasticsearch 7.x

  • Specifying types in requests is deprecated. For instance, indexing a document no longer requires a document type. The new index APIs are PUT {index}/_doc/{id} in case of explicit ids and POST {index}/_doc for auto-generated ids. Note that in 7.0, _doc is a permanent part of the path, and represents the endpoint name rather than the document type.
  • The include_type_name parameter in the index creation, index template, and mapping APIs will default to false. Setting the parameter at all will result in a deprecation warning.
  • The _default_ mapping type is removed.

Elasticsearch 8.x

  • Specifying types in requests is no longer supported.
  • The include_type_name parameter is removed.
  1. 关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。

    • 两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
    • 去掉type就是为了提高ES处理数据的效率。
  2. Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。

  3. Elasticsearch 8.x 不再支持URL中的type参数。

  4. 解决:
    将索引从多类型迁移到单类型,每种类型文档一个独立索引

    将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移

3.3 文档 Doc——>类比于数据库表中的一个个数据

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

文档
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yDfqNeo2-1615968962511)(es文档图片\1587048972631.png)]

3.4 属性 Field——>类比于数据库表中的行数据的不同字段

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

属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EcszNH40-1615968962513)(es文档图片\1587049031609.png)]

四、Docker安装ES和Kibana

4.1安装es

方法一:

拉取镜像

-> docker pull elasticsearch:7.5.1  #安装从es,存储和检索数据

创建实例

#创建Linux系统下创建两个文件夹用作es容器启动后外部挂载
#可以方便以后在外部Linux系统下通过对配置文件和数据的修改同步到es容器中
-> mkdir -p /mydata/elasticsearch/config
-> mkdir -p /mydata/elasticsearch/data#修改yml文件让es可以被远程端任何机器进行访问
-> echo "http.host:0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml

elasticsearch.yml文件内容!!!一定要注意不能有错!否则容器无法启动!

# 集群名称
cluster.name: elasticsearch‐cluster
# 节点名称
node.name: es‐node1
# 绑定host,0.0.0.0代表当前节点的ip
network.host: 0.0.0.0
# 设置其它节点和该节点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址(本机ip)
network.publish_host: 192.168.2.32
# 设置对外服务的http端口,默认为9200
http.port: 9200
http.host: 0.0.0.0
# 设置节点间交互的tcp端口,默认是9300
transport.tcp.port: 9300
# 是否支持跨域,默认为false
http.cors.enabled: true
# 当设置允许跨域,默认为*,表示支持所有域名,如果我们只是允许某些网站能访问,那么可以使用正则表达式。比如只允许本地 地址。 /https?:\/\/localhost(:[0‐9]+)?/
http.cors.allow‐origin: "*"
# 表示这个节点是否可以充当主节点
node.master: true
# 是否充当数据节点
node.data: true
# 所有主从节点ip:port
discovery.seed_hosts: ["192.168.2.32:9300"]
# 这个参数决定了在选主过程中需要 有多少个节点通信 预防脑裂
discovery.zen.minimum_master_nodes: 1

修改文件权限

#授权,给任何人都有读、写、运行三项权限-> chmod 777 /mydata/elasticsearch/data
-> chmod 777 /mydata/elasticsearch/config/elasticsearch.yml
-> chmod 777 /mydata/elasticsearch/plugins

启动命令

# -p 9300:9300 ES在分布式时候通信时候的端口 -p 9200:9200 ES自己的端口
# -e "discovery.type=single‐node":以单节点模式运行
# ‐e ES_JAVA_OPTS="‐Xms64m ‐Xmx256m":规定初始内存
# ‐v /mydata/elasticsearch/config/... :下面三个步骤代表挂载配置,挂到外部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.5.1

PS:当容器无法启动时,可以通过 docker logs [容器id] 命令进行查看错误原因

​ 上述方法容器成功启动无报错,但是外部无法访问,跨域、http.host也进行了设置,应该是电脑问题。。。网上也查不到原因,方法应该没有问题,可能是启服务时,一直是满载运行导致这个结果。此方法好处在于可以通过外部linux下的文件很方便的修改容器内的配置和文件

方法二:

拉取镜像

-> docker pull elasticsearch:7.5.1

启动es

-> docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.5.1

修改配置,解决跨域问题

首先进入到容器中,然后进入到指定目录修改elasticsearch.yml文件。

-> docker exec -it elasticsearch /bin/bash
-> cd /usr/share/elasticsearch/config/
-> vim elasticsearch.yml# 追加一下内容,解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
# 重启容器
-> exit
-> docker restart elasticsearch

4.2安装分词器

es自带的分词器对中文分词不是很友好,所以我们下载开源的IK分词器来解决这个问题。首先进入到plugins目录中下载分词器,下载完成后然后解压,再重启es即可。具体步骤如下:
注意:elasticsearch的版本和ik分词器的版本需要保持一致,不然在重启的时候会失败。可以在这查看所有版本,选择合适自己版本的右键复制链接地址即可。点击这里

-> cd /usr/share/elasticsearch/plugins/
-> elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.1/elasticsearch-analysis-ik-7.5.1.zip
-> exit
-> docker restart elasticsearch

然后可以在kibana界面的dev tools中验证是否安装成功;

4.3安装kibana

-> docker pull kibana:7.5.1  #安装从kibana,可视化界面检索数据,版本号保持一致

启动kibana

-> docker run --name kibana --link=elasticsearch:test  -p 5601:5601 -d kibana:7.5.1
-> docker start kibana
或者(二选一)
-> docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.2.32:9200 -p 5601:5601 -d kibana:7.5.1

五、操作ES的RESTful语法

index:索引库名称;type:类型;doc_id:文档id

  • GET请求:

    • http://ip:port/_cat/nodes:查看所有节点

    • http://ip:port/_cat/health:查看es健康状况

    • http://ip:port/_cat/master:查看主节点

    • http://ip:port/_cat/indices:查看所有索引

    • 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请求:(PUT请求与POST)请求区别,PUT必须带doc_id,POST如果不带id会自动生成随机id

    • http://ip:port/index:创建一个索引,需要在请求体中指定索引的信息,类型,结构
    • http://ip:port/index/type/_mappings:代表创建索引时,指定索引文档存储的属性的信息
  • DELETE请求:

    • http://ip:port/index:删除索引
    • http://ip:port/index/type/doc_id:删除指定的文档

5.1索引的操作

Kibana的Dev Tools中进行如下操作

5.1.1创建一个索引
# 创建一个索引
PUT /person
{"settings": {#分片数"number_of_shards": 5,#备份数"number_of_replicas": 1}
}
5.1.2 查看索引信息
# 查看索引信息
GET /person
5.1.3删除索引
# 删除索引
DELETE /person
5.1.4 创建索引
# 创建索引,指定数据结构
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 ,# 是否需要额外存储"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"}}}}
}

5.2 文档的操作

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

5.2.1 新建文档

自动生成_id

# 添加文档,自动生成id
POST /book/novel
{"name": "西游记","author": "吴承恩","count": 100000,"descr": "白龙马蹄朝西"
}

手动指定_id

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

覆盖式修改

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

doc修改方式

# 修改文档,基于doc方式
POST /book/novel/1/_update
{"doc": {# 指定上需要修改的field和对应的值"count": "1234565"}
}
5.2.3 删除文档

根据id删除

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

5.3 高级检索

5.3.1 批量操作 _bulk

这里的批量操作,当发生某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的。

bulk api以此按顺序执行所有的action(动作)。如果一个单个的动作因任何原因失败,它将继续处理它后面剩余的动作。当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了。

{action:{metadata}}
{request body  }{action:{metadata}}
{request body  }

**案例1:**执行多条数据

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

**案例2:**对于整个索引执行批量操作

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"}}
5.3.2 Search Api

测试数据

https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json 导入测试数据

POST bank/account/_bulk

ES支持两种基本方式检索;

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

uri+请求体进行检索

GET /bank/_search
{"query": { "match_all": {} },"sort": [{ "account_number": "asc" },{"balance":"desc"}]
}

uri +检索参数进行检索

GET bank/_search?q=*&sort=account_number:asc

检索结果:

{"took" : 26,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1000,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "bank","_type" : "count","_id" : "0","_score" : null,"_source" : {"account_number" : 0,"balance" : 16623,"firstname" : "Bradshaw","lastname" : "Mckenzie","age" : 29,"gender" : "F","address" : "244 Columbus Place","employer" : "Euron","email" : "bradshawmckenzie@euron.com","city" : "Hobucken","state" : "CO"},"sort" : [0]},{"_index" : "bank","_type" : "count","_id" : "1","_score" : null,"_source" : {"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"},"sort" : [1]},{"_index" : "bank","_type" : "count","_id" : "2","_score" : null,"_source" : {"account_number" : 2,"balance" : 28838,"firstname" : "Roberta","lastname" : "Bender","age" : 22,"gender" : "F","address" : "560 Kingsway Place","employer" : "Chillium","email" : "robertabender@chillium.com","city" : "Bennett","state" : "LA"},"sort" : [2]}....]}
}

检索结果中各参数介绍:

  • took Elasticsearch 执行的搜索毫秒
  • timed_out 告诉我们搜索是否超时
  • _shards 告诉我多少分片被搜索了,并且统计了成功失败的搜索分片
  • max_scorescore 最高分和相关性得分
  • hits.total.value 有多少符合条件的搜索结果
  • hits 搜索结果
  • sort 结果排序key(键)
5.3.3 Query DSL

Elasticsearch提供了一个可以执行查询的Json风格的DSL。这个被称为Query DSL,该查询语言非常全面。

(1)基本语法格式

一个查询语句的典型结构

QUERY_NAME:{ARGUMENT:VALUE,ARGUMENT:VALUE,...
}

如果针对于某个字段,那么它的结构如下:

{QUERY_NAME:{FIELD_NAME:{ARGUMENT:VALUE,ARGUMENT:VALUE,...}   }
}

案例一:分页排序查询

GET bank/_search
{"query": {"match_all": {}},"from": 0,    #从第几条数据开始"size": 5,   #往后显示几条数据"sort": [{"account_number": {"order": "desc"}}]
}

query定义如何查询;

  • match_all查询类型【代表查询所有的所有】,es中可以在query中组合非常多的查询类型完成复杂查询;
  • 除了query参数之外,我们可也传递其他的参数以改变查询结果,如sort,size;
  • from+size限定,完成分页功能;
  • sort排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准;

(2)返回部分字段

GET bank/_search
{"query": {"match_all": {}},"from": 0,"size": 5,"sort": [{"account_number": {"order": "desc"}}],"_source": ["balance","firstname"] #选择返回的字段
}

(3)match匹配查询

基本数据类型(非字符串),精确查询

GET bank/_search
{"query": {"match": {"account_number": "20"  #match返回account_number=20的数据}}
}

字符串类型,全文检索

GET /bank/_search
{"query": {"match": {"address": "mill lane"     #match字符串匹配查询,返回值中会按score命中评分来进行排序} }
}

(4) match_phrase [短句匹配]

将需要匹配的值当成一整个单词(不会进行分词)进行检索

GET /bank/_search
{"query": { "match_phrase": { "address": "mill lane" #match_phrase匹配查询,不会对mill lane进行分词,当作整体进行查询} }
}

和使用match的keyword查询区别

GET bank/_search
{"query": {"match_phrase": {#会将"990 Mill"看作整体进行查询,只要部分包含990 Mill就会被当作结果返回"address": "990 Mill"  }}
}
GET bank/_search
{"query": {"match": {#使用.keyword就将900 Mill当作精确查询,只有完全匹配的结果才会被返回"address.keyword": "990 Mill"}}
}

(5)multi_math【多字段匹配】

GET bank/_search
{"query": {"multi_match": {"query": "mill","fields": [        "state","address"]}}
}

state或者address中包含mill,并且在查询过程中,会对于查询条件进行分词。

(6)bool用来做复合查询(重点!!实际业务场景中多用此类查询!)

复合语句可以合并,任何其他查询语句,包括符合语句。这也就意味着,复合语句之间
可以互相嵌套,可以表达非常复杂的逻辑。

must:必须达到must所列举的所有条件。

must_not:必须不匹配must_not所列举的所有条件。

should:应该满足should所列举的条件。

**must:**必须达到条件

GET bank/_search
{"query":{"bool":{"must":[                            #查询gender=M,并且address=mill的数据{"match":{"address":"mill"          }},{"match":{"gender":"M"}}]}}
}

**must_not:**必须是刨除指定的情况返回剩余结果

GET bank/_search
{"query": {"bool": {"must": [{"match": {"gender": "M"}},{"match": {"address": "mill"}}],"must_not": [               #查询gender=m,并且address=mill的数据,但是age不等于38的{"match": {"age": "38"}}]}}

**should:**应该匹配的查询条件,不影响整体查询结果,会影响score得分进而影响最后查询的顺序。

应该达到should列举的条件,如果到达会增加相关文档的评分,并不会改变查询的结果。如果query中只有should且只有一种匹配规则,那么should的条件就会被作为默认匹配条件而区改变查询结果。

GET bank/_search
{"query": {"bool": {"must": [{"match": {"gender": "M"}},{"match": {"address": "mill"}}],"must_not": [{"match": {"age": "18"}}],"should": [{"match": {"lastname": "Wallace"      #结果中能够看到相关度越高,得分也越高。}}]}}
}

小结(文档翻译)

Each must, should, and must_not element in a Boolean query is referred to as a query clause. How well a document meets the criteria in each must or should clause contributes to the document’s relevance score. The higher the score, the better the document matches your search criteria. By default, Elasticsearch returns documents ranked by these relevance scores.

在boolean查询中,must, shouldmust_not 元素都被称为查询子句 。 文档是否符合个“must”或“should”子句中的标准,决定了文档的“相关性得分”。 得分越高,文档越符合您的搜索条件。 默认情况下,Elasticsearch返回根据这些相关性得分排序的文档。

The criteria in a must_not clause is treated as a filter. It affects whether or not the document is included in the results, but does not contribute to how documents are scored. You can also explicitly specify arbitrary filters to include or exclude documents based on structured data.

“must_not”子句中的条件被视为“过滤器”。 它影响文档是否包含在结果中, 但不影响文档的评分方式。 还可以显式地指定任意过滤器来包含或排除基于结构化数据的文档。

(7)Filter(结果过滤)

并不是所有的查询都需要产生分数,特别是哪些仅用于filter过滤的文档。为了不计算分数,elasticsearch会自动检查场景并且优化查询的执行。

#这里先是查询所有匹配address=mill的文档,然后再根据10000<=balance<=20000进行过滤查询结果
GET bank/_search
{"query": {"bool": {"must": [{"match": {"address": "mill"}}],"filter": {"range": {"balance": {"gte": "10000","lte": "20000"}}}}}
}

结果:

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 5.4032025,    #显而易见在must的使用下filter过滤还是有查询得分的"hits" : [{"_index" : "bank","_type" : "count","_id" : "970","_score" : 5.4032025,"_source" : {"account_number" : 970,"balance" : 19648,"firstname" : "Forbes","lastname" : "Wallace","age" : 28,"gender" : "M","address" : "990 Mill Road","employer" : "Pheast","email" : "forbeswallace@pheast.com","city" : "Lopezo","state" : "AK"}}]}
}

对比========>:

GET bank/_search
{"query": {"bool": {"filter": {"range": {"balance": {"gte": "10000","lte": "20000"}}}}}
}

结果:

{"took" : 4,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 213,"relation" : "eq"},"max_score" : 0.0,   #显而易见在filter过滤使用中会消除得分,看到所有文档的 “_score” : 0.0"hits" : [{"_index" : "bank","_type" : "count","_id" : "20","_score" : 0.0,"_source" : {"account_number" : 20,"balance" : 16418,"firstname" : "Elinor","lastname" : "Ratliff","age" : 36,"gender" : "M","address" : "282 Kings Place","employer" : "Scentric","email" : "elinorratliff@scentric.com","city" : "Ribera","state" : "WA"}},{"_index" : "bank","_type" : "count","_id" : "37","_score" : 0.0,"_source" : {"account_number" : 37,"balance" : 18612,"firstname" : "Mcgee","lastname" : "Mooney","age" : 39,"gender" : "M","address" : "826 Fillmore Place","employer" : "Reversus","email" : "mcgeemooney@reversus.com","city" : "Tooleville","state" : "OK"}....}}]}
}

(8)term

和match一样。对field进行匹配查询。全文检索字段用match,其他非text字段匹配用term。

官方文档中做出了对match和term的如下解释:

Avoid using the term query for text fields.

避免对文本字段使用“term”查询

By default, Elasticsearch changes the values of text fields as part of analysis. This can make finding exact matches for text field values difficult.

默认情况下,Elasticsearch更改作为analysis的一部分’ text '字段的值,这使得为“text”字段值寻找精确匹配变得困难。

To search text field values, use the match.

要搜索“text”字段值,请使用match。

使用term匹配查询:

GET bank/_search
{"query": {"term": {"address": "mill Road"}}
}

结果(注意!):

{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 0,"relation" : "eq"},"max_score" : null,"hits" : [ ]}
}

一条也没有匹配到!而改用match可以匹配到结果文档。

也就是说,全文检索字段用match,其他非text字段匹配用term

(9)Aggregation(执行聚合)

​ 聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致类比于于SQL Group by和SQL聚合函数。在elasticsearch中,执行搜索返回this(命中结果),并且同时返回聚合结果,把以响应中的所有hits(命中结果)分隔开的能力。这是非常强大且有效的,你可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的API,避免网络传输的往返。

​ aggs:执行聚合。聚合语法如下:

"aggs":{"aggs_name这次聚合的名字,方便展示在结果集中":{"AGG_TYPE聚合的类型(avg,term,terms)":{}}
},
“size”:0        #不显示搜索数据

搜索address中包含mill的所有人的年龄分布以及平均年龄,但不显示这些人的详情:

GET bank/_search
{"query": {"match": {"address": "Mill"}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 10}},"ageAvg": {"avg": {"field": "age"}},"balanceAvg": {"avg": {"field": "balance"}}},"size": 0
}

结果:

{"took" : 2,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 4,"relation" : "eq"},"max_score" : null,"hits" : [ ]},"aggregations" : {"ageAgg" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : 38,               #对应field的值"doc_count" : 2         #查询出来命中文档的数量},{"key" : 28,"doc_count" : 1},{"key" : 32,"doc_count" : 1}]},"ageAvg" : {"value" : 34.0},"balanceAvg" : {"value" : 25208.0}}
}

复杂嵌套查询

按照年龄聚合,并且求这些年龄段的这些人的平均薪资

GET bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"ageBalanceAvg": {"avg": {"field": "balance"}}}}},"size": 0
}

结果:

{"took" : 44,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1000,"relation" : "eq"},"max_score" : null,"hits" : [ ]},"aggregations" : {"ageAgg" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : 31,"doc_count" : 61,"ageBalanceAvg" : {"value" : 28312.918032786885}},{"key" : 39,"doc_count" : 60,"ageBalanceAvg" : {"value" : 25269.583333333332}},{"key" : 26,"doc_count" : 59,"ageBalanceAvg" : {"value" : 23194.813559322032}}......]}}
}

查出所有年龄分布,并且查询出这些年龄段中性别为M的平均薪资和性别为F的平均薪资以及这个年龄段的总体平均薪资

GET bank/_search
{"query": {"match_all": {}},"aggs": {"ageAgg": {"terms": {"field": "age","size": 100},"aggs": {"genderAgg": {"terms": {"field": "gender.keyword"},"aggs": {"balanceAvg": {"avg": {"field": "balance"}}}},"ageBalanceAvg": {"avg": {"field": "balance"}}}}},"size": 0
}

结果:

{"took" : 119,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1000,"relation" : "eq"},"max_score" : null,"hits" : [ ]},"aggregations" : {"ageAgg" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : 31,"doc_count" : 61,"genderAgg" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "M","doc_count" : 35,"balanceAvg" : {"value" : 29565.628571428573}},{"key" : "F","doc_count" : 26,"balanceAvg" : {"value" : 26626.576923076922}}]},"ageBalanceAvg" : {"value" : 28312.918032786885}}]...  ...}}
}
5.3.4 Mapping

(1)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

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

(2)映射

Mapping(映射)
Maping是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。比如:使用maping来定义:

  • 哪些字符串属性应该被看做全文本属性(full text fields);
  • 哪些属性包含数字,日期或地理位置;
  • 文档中的所有属性是否都嫩被索引(all 配置);
  • 日期的格式;
  • 自定义映射规则来执行动态添加属性;

查看mapping信息

GET bank/_mapping

创建mapping信息

PUT /my-index-000001
{"mappings": {"properties": {"age":    { "type": "integer" },  "email":  { "type": "keyword"  }, "name":   { "type": "text"  }     }}
}

增加一个mapping信息

PUT /my-index-000001/_mapping
{"properties": {"employee-id": {"type": "keyword",
#"index"控制对该字段是否建立索引,index映射参数值为false意味着该employee-id字段的值已存储,但未索引或不可搜索"index": false  }}
}

更新一个mapping信息

**官网给的解释:**对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移。(总而言之,不好修改)

Except for supported mapping parameters, you can’t change the mapping or field type of an existing field. Changing an existing field could invalidate data that’s already indexed.

If you need to change the mapping of a field in a data stream’s backing indices, see Change mappings and settings for a data stream.

If you need to change the mapping of a field in other indices, create a new index with the correct mapping and reindex your data into that index.

Renaming a field would invalidate data already indexed under the old field name. Instead, add an alias field to create an alternate field name.

除了支持的映射参数外,不能更改现有字段的映射或字段类型。更改现有字段可能会使已存的索引的数据无效。

如果需要更改数据流支持索引中字段的映射,请参阅更改数据流的映射和设置。

如果需要更改字段在其他索引中的映射,请使用正确的映射创建一个新索引,并将数据重新索引到该索引中。

重命名字段会使已在旧字段名下编制索引的数据无效。相反,请添加别名字段以创建备用字段名。

延申:数据迁移

先创建new_twitter的正确映射。然后使用如下方式进行数据迁移。

POST reindex #固定写法
{"source":{"index":"twitter"},"dest":{"index":"new_twitters"}
}

将旧索引的type下的数据进行迁移

POST reindex [固定写法]
{"source":{"index":"twitter","type":"twitter_type"},"dest":{"index":"new_twitters"}
}

更多的前往:https://www.elastic.co/guide/en/elasticsearch/reference/7.6/docs-reindex.html

六、SpringBoot整合ElasticSearch

6.1 基于spring-boot-starter-data-elasticsearch整合的api

6.1.1 导入依赖pom
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
6.1.2 setting文件配置(resources文件夹下)
{"index": {#max_result_window设置的数量是es对from+size的大小进行限制,一般设置为最大,数据类型为                Integer,最大上限20亿"max_result_window": 2000000000 }
}
6.1.3 application.yml配置
spring:elasticsearch:rest:uris:    #配置es地址,可以是多个username:password:
6.1.4 建立ES实体
@Data
//通过这个注解可以声明一个文档,指定其所在的索引库和type,指定分片数和备份数
@Document(indexName = "test_doc",type = "testbean", shards = 2, replicas = 2)
//将配置文件的配置加进来
@Setting(settingPath = "settings/elasticsearch-setting.json")
public class TestBean implements Serializable {public TestBean() {}public TestBean(long id, String name, Integer age, String sex, String desc) {this.id = id;this.name = name;this.age = age;this.sex = sex;this.desc = desc;}// 必须指定一个id,@Idprivate long id;// 这里设置了字段类型,可以不配置,默认也可,还可以设置选区的分词器@Field(type = FieldType.Keyword)private String name;private Integer age;@Field(type = FieldType.Keyword)private String sex;@Field(type = FieldType.Text,, analyzer = "ik_max_word")private String desc;
}
6.1.5 ES查询dao层写法
//继承ElasticsearchRepository,并拥有自带增删改查方法
@Component
public interface TestDao extends ElasticsearchRepository<TestBean,String>{}
6.1.6 建立索引
IndexOperations indexOps = elasticsearchRestTemplate.indexOps(TestBean.class);
//indexOps.delete(); 删除之前旧的索引库
indexOps.create();
indexOps.putMapping(indexOps.createMapping());//创建索引

更多查询操作api参考官方文档或百度查询:

官方文档:https://docs.spring.io/spring-data/elasticsearch/docs/4.1.2/reference/html/#elasticsearch.operations.searchresulttypes

官方API:https://docs.spring.io/spring-data/elasticsearch/docs/4.1.2/api/

6.2 基于es的elasticsearch-rest-high-level-client包整合的基础API

6.2.1 导入依赖pom
    <!--elasticsearch--><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.5.1</version></dependency><!--elasticsearch的高级API--><dependency>    <groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.5.1</version></dependency>

创建测试类,连接ES

public class ESClient {public static RestHighLevelClient getClient(){// 创建HttpHost对象HttpHost httpHost = new HttpHost("192.168.2.32",9200);// 创建RestClientBuilderRestClientBuilder clientBuilder = RestClient.builder(httpHost);// 创建RestHighLevelClientRestHighLevelClient client = new RestHighLevelClient(clientBuilder);// 返回return client;}}
6.2.2 创建索引

代码如下

public class Demo2 {RestHighLevelClient client = ESClient.getClient();String index = "person";String type = "man";@Testpublic void createIndex() throws IOException {//1. 准备关于索引的settingsSettings.Builder settings = Settings.builder().put("number_of_shards", 3).put("number_of_replicas", 1);//2. 准备关于索引的结构mappingsXContentBuilder 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());}}
6.2.3 检查索引是否存在

代码如下

@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);
}
6.2.4 删除索引

代码如下

@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());
}
6.2.5 添加文档操作

代码如下

public class Demo3 {ObjectMapper mapper = new ObjectMapper();RestHighLevelClient client = ESClient.getClient();String index = "person";String type = "man";@Testpublic void createDoc() throws IOException {//1. 准备一个json数据Person person = new Person(1,"张三",23,new Date());String json = mapper.writeValueAsString(person);//2. 准备一个request对象(手动指定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());}}
6.2.6 修改文档

代码如下

@Test
public void updateDoc() throws IOException {//1. 创建一个Map,指定需要修改的内容Map<String,Object> doc = new HashMap<>();doc.put("name","张大三");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());
}
6.2.7 删除文档

代码如下

@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());
}
6.2.8 批量添加

代码如下

@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());
}
6.2.9 批量删除

代码如下

@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);
}

前置操作:

创建索引,指定数据结构

索引名:sms-logs-index

类型名:sms-logs-type

结构如下:

索引结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQkM8gCz-1615968962515)(C:\Users\Administrator\Pictureses文档图片/1587137696912.png)]
6.2.10 term查询

代码如下

// 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);}
}
6.2.11 terms查询

代码如下

// Java实现
@Test
public void termsQuery() throws IOException {//1. 创建requestSearchRequest 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. 输出_sourcefor (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.2.12 match_all查询

代码如下

//  java代码实现
@Test
public void matchAllQuery() throws IOException {//1. 创建RequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.matchAllQuery());builder.size(20);           // ES默认只查询10条数据,如果想查询更多,添加sizerequest.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.13 match查询

代码如下

@Test
public void matchQuery() throws IOException {//1. 创建RequestSearchRequest 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().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.2.14 布尔match查询

代码如下

// Java代码实现
@Test
public void booleanMatchQuery() throws IOException {//1. 创建RequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//-----------------------------------------------                               选择AND或者ORbuilder.query(QueryBuilders.matchQuery("smsContent","中国 健康").operator(Operator.OR));//-----------------------------------------------request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}

rest请求如下:基于一个Field匹配的内容,采用and或者or的方式连接

# 布尔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"     # 内容包括健康或者包括中国}}}
}
6.2.15 multi_match查询

代码如下

// java代码实现
@Test
public void multiMatchQuery() throws IOException {//1. 创建RequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//-----------------------------------------------builder.query(QueryBuilders.multiMatchQuery("北京","province","smsContent"));//-----------------------------------------------request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}

6.3 基于es的elasticsearch-rest-high-level-client包整合的高级查询API

6.3.1 id查询

根据id查询 where id = ?

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

代码实现方式

// Java代码实现
@Test
public void findById() throws IOException {//1. 创建GetRequestGetRequest request = new GetRequest(index,type,"1");//2. 执行查询GetResponse resp = client.get(request, RequestOptions.DEFAULT);//3. 输出结果System.out.println(resp.getSourceAsMap());
}
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"]}}
}

代码实现方式

// Java代码实现
@Test
public void findByIds() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.idsQuery().addIds("1","2","3"));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.3.3 prefix查询

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

#prefix 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"prefix": {"corpName": {"value": "途虎"}}}
}

代码实现方式

// Java实现前缀查询
@Test
public void findByPrefix() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.prefixQuery("corpName","盒马"));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.3.4 fuzzy查询

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

# fuzzy查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"fuzzy": {"corpName": {"value": "盒马先生","prefix_length": 2            # 指定前面几个字符是不允许出现错误的}}}
}

代码实现方式

// Java代码实现Fuzzy查询
@Test
public void findByFuzzy() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.fuzzyQuery("corpName","盒马先生").prefixLength(2));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.3.5 wildcard查询

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

# wildcard 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"wildcard": {"corpName": {"value": "中国*"    # 可以使用*和?指定通配符和占位符}}}
}

代码实现方式

// Java代码实现Wildcard查询
@Test
public void findByWildCard() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.wildcardQuery("corpName","中国*"));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
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:<=}}}
}

代码实现方式

// Java实现range范围查询
@Test
public void findByRange() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.rangeQuery("fee").lte(10).gte(5));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.3.7 regexp查询

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

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

# regexp 查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"regexp": {"mobile": "180[0-9]{8}"    # 编写正则}}
}

代码实现方式

// Java代码实现正则查询
@Test
public void findByRegexp() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();//----------------------------------------------------------builder.query(QueryBuilders.regexpQuery("mobile","139[0-9]{8}"));//----------------------------------------------------------request.source(builder);//3. 执行SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.3.8 深分页Scroll

ES对from + size是有限制的,from和size二者之和不能超过1W

原理:

  • from+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。
    • 第三步去各个分片中去拉取指定的数据。耗时较长。
    • 第四步将数据根据score进行排序。耗时较长。
    • 第五步根据from的值,将查询到的数据舍弃一部分。
    • 第六步返回结果。
  • scroll+size在ES查询数据的方式:

    • 第一步现将用户指定的关键进行分词。
    • 第二步将词汇去分词库中进行检索,得到多个文档的id。
    • 第三步将文档的id存放在一个ES的上下文中。
    • 第四步根据你指定的size的个数去ES中检索指定个数的数据,拿完数据的文档id,会从上下文中移除。
    • 第五步如果需要下一页数据,直接去ES的上下文中,找后续内容。
    • 第六步循环第四步和第五步

Scroll查询方式,不适合做实时的查询

# 执行scroll查询,返回第一页数据,并且将文档id信息存放在ES上下文中,指定生存时间1m
POST /sms-logs-index/sms-logs-type/_search?scroll=1m
{"query": {"match_all": {}},"size": 2,"sort": [                 # 排序{"fee": {"order": "desc"}}]
}# 根据scroll查询下一页数据
POST /_search/scroll
{"scroll_id": "<根据第一步得到的scorll_id去指定>","scroll": "<scorll信息的生存时间>"
}# 删除scroll在ES上下文中的数据
DELETE /_search/scroll/scroll_id

代码实现方式

// Java实现scroll分页
@Test
public void scrollQuery() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定scroll信息request.scroll(TimeValue.timeValueMinutes(1L));//3. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();builder.size(4);builder.sort("fee", SortOrder.DESC);builder.query(QueryBuilders.matchAllQuery());request.source(builder);//4. 获取返回结果scrollId,sourceSearchResponse resp = client.search(request, RequestOptions.DEFAULT);String scrollId = resp.getScrollId();System.out.println("----------首页---------");for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}while(true) {//5. 循环 - 创建SearchScrollRequestSearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);//6. 指定scrollId的生存时间scrollRequest.scroll(TimeValue.timeValueMinutes(1L));//7. 执行查询获取返回结果SearchResponse scrollResp = client.scroll(scrollRequest, RequestOptions.DEFAULT);//8. 判断是否查询到了数据,输出SearchHit[] hits = scrollResp.getHits().getHits();if(hits != null && hits.length > 0) {System.out.println("----------下一页---------");for (SearchHit hit : hits) {System.out.println(hit.getSourceAsMap());}}else{//9. 判断没有查询到数据-退出循环System.out.println("----------结束---------");break;}}//10. 创建CLearScrollRequestClearScrollRequest clearScrollRequest = new ClearScrollRequest();//11. 指定ScrollIdclearScrollRequest.addScrollId(scrollId);//12. 删除ScrollIdClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);//13. 输出结果System.out.println("删除scroll:" + clearScrollResponse.isSucceeded());}
6.3.9 delete-by-query

根据term,match等查询方式去删除大量的文档

Ps:如果你需要删除的内容,是index下的大部分数据,推荐创建一个全新的index,将保留的文档内容,添加到全新的索引

# delete-by-query
POST /sms-logs-index/sms-logs-type/_delete_by_query
{"query": {"range": {"fee": {"lt": 4}}}
}

代码实现方式

// Java代码实现
@Test
public void deleteByQuery() throws IOException {//1. 创建DeleteByQueryRequestDeleteByQueryRequest request = new DeleteByQueryRequest(index);request.types(type);//2. 指定检索的条件    和SearchRequest指定Query的方式不一样request.setQuery(QueryBuilders.rangeQuery("fee").lt(4));//3. 执行删除BulkByScrollResponse resp = client.deleteByQuery(request, RequestOptions.DEFAULT);//4. 输出返回结果System.out.println(resp.toString());}

6.4 基于es的elasticsearch-rest-high-level-client包整合的复合查询API

6.4.1 bool查询

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

  • must: 所有的条件,用must组合在一起,表示And的意思
  • must_not:将must_not中的条件,全部都不能匹配,标识Not的意思
  • should:所有的条件,用should组合在一起,表示Or的意思
# 查询省份为武汉或者北京
# 运营商不是联通
# smsContent中包含中国和平安
# bool查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"bool": {"should": [{"term": {"province": {"value": "北京"}}},{"term": {"province": {"value": "武汉"}}}],"must_not": [{"term": {"operatorId": {"value": "2"}}}],"must": [{"match": {"smsContent": "中国"}},{"match": {"smsContent": "平安"}}]}}
}

代码实现方式

// Java代码实现Bool查询
@Test
public void BoolQuery() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();// # 查询省份为武汉或者北京boolQuery.should(QueryBuilders.termQuery("province","武汉"));boolQuery.should(QueryBuilders.termQuery("province","北京"));// # 运营商不是联通boolQuery.mustNot(QueryBuilders.termQuery("operatorId",2));// # smsContent中包含中国和平安boolQuery.must(QueryBuilders.matchQuery("smsContent","中国"));boolQuery.must(QueryBuilders.matchQuery("smsContent","平安"));builder.query(boolQuery);request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
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}}
}

代码实现方式

// Java实现Boosting查询
@Test
public void BoostingQuery() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件SearchSourceBuilder builder = new SearchSourceBuilder();BoostingQueryBuilder boostingQuery = QueryBuilders.boostingQuery(QueryBuilders.matchQuery("smsContent", "收货安装"),QueryBuilders.matchQuery("smsContent", "王五")).negativeBoost(0.5f);builder.query(boostingQuery);request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}
6.4.3 filter查询
# filter查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"bool": {"filter": [{"term": {"corpName": "盒马鲜生"}},{"range": {"fee": {"lte": 4}}}]}}
}

代码如下

// Java实现filter操作
@Test
public void filter() throws IOException {//1. SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 查询条件SearchSourceBuilder builder = new SearchSourceBuilder();BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();boolQuery.filter(QueryBuilders.termQuery("corpName","盒马鲜生"));boolQuery.filter(QueryBuilders.rangeQuery("fee").lte(5));builder.query(boolQuery);request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}
6.4.5 高亮查询

高亮查询就是你用户输入的关键字,以一定的特殊样式展示给用户,让用户知道为什么这个结果被检索出来。

高亮展示的数据,本身就是文档中的一个Field,单独将Field以highlight的形式返回给你。

ES提供了一个highlight属性,和query同级别的。

  • fragment_size:指定高亮数据展示多少个字符回来。
  • pre_tags:指定前缀标签,举个栗子< font color=“red” >
  • post_tags:指定后缀标签,举个栗子< /font >
  • fields:指定哪几个Field以高亮形式返回

RESTful实现

# highlight查询
POST /sms-logs-index/sms-logs-type/_search
{"query": {"match": {"smsContent": "盒马"}},"highlight": {"fields": {"smsContent": {}},"pre_tags": "<font color='red'>","post_tags": "</font>","fragment_size": 10}
}

代码实现方式

// Java实现高亮查询
@Test
public void highLightQuery() throws IOException {//1. SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定查询条件(高亮)SearchSourceBuilder builder = new SearchSourceBuilder();//2.1 指定查询条件builder.query(QueryBuilders.matchQuery("smsContent","盒马"));//2.2 指定高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("smsContent",10).preTags("<font color='red'>").postTags("</font>");builder.highlighter(highlightBuilder);request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 获取高亮数据,输出for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getHighlightFields().get("smsContent"));}
}

6.5 基于es的elasticsearch-rest-high-level-client包整合的聚合查询API

6.5.1 去重计数查询

去重计数,即Cardinality,第一步先将返回的文档中的一个指定的field进行去重,统计一共有多少条

# 去重计数查询 北京 上海 武汉 山西
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"cardinality": {"field": "province"}}}
}

代码实现方式

//  Java代码实现去重计数查询
@Test
public void cardinality() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定使用的聚合查询方式SearchSourceBuilder builder = new SearchSourceBuilder();builder.aggregation(AggregationBuilders.cardinality("agg").field("province"));request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 获取返回结果Cardinality agg = resp.getAggregations().get("agg");long value = agg.getValue();System.out.println(value);
}
6.5.2 范围统计

统计一定范围内出现的文档个数,比如,针对某一个Field的值在 0100,100200,200~300之间文档出现的个数分别是多少。

范围统计可以针对普通的数值,针对时间类型,针对ip类型都可以做相应的统计。

range,date_range,ip_range

数值统计

# 数值方式范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"range": {"field": "fee","ranges": [{"to": 5},{"from": 5,    # from有包含当前值的意思  "to": 10},{"from": 10}]}}}
}

时间范围统计

# 时间方式范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"date_range": {"field": "createDate","format": "yyyy", "ranges": [{"to": 2000},{"from": 2000}]}}}
}

ip统计方式

# ip方式 范围统计
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"ip_range": {"field": "ipAddr","ranges": [{"to": "10.126.2.9"},{"from": "10.126.2.9"}]}}}
}

代码实现方式

// Java实现数值 范围统计
@Test
public void range() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定使用的聚合查询方式SearchSourceBuilder builder = new SearchSourceBuilder();//---------------------------------------------builder.aggregation(AggregationBuilders.range("agg").field("fee").addUnboundedTo(5).addRange(5,10).addUnboundedFrom(10));//---------------------------------------------request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 获取返回结果Range agg = resp.getAggregations().get("agg");for (Range.Bucket bucket : agg.getBuckets()) {String key = bucket.getKeyAsString();Object from = bucket.getFrom();Object to = bucket.getTo();long docCount = bucket.getDocCount();System.out.println(String.format("key:%s,from:%s,to:%s,docCount:%s",key,from,to,docCount));}
}
6.5.3 统计聚合查询

他可以帮你查询指定Field的最大值,最小值,平均值,平方和等

使用:extended_stats

# 统计聚合查询
POST /sms-logs-index/sms-logs-type/_search
{"aggs": {"agg": {"extended_stats": {"field": "fee"}}}
}

代码实现方式

// Java实现统计聚合查询
@Test
public void extendedStats() throws IOException {//1. 创建SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定使用的聚合查询方式SearchSourceBuilder builder = new SearchSourceBuilder();//---------------------------------------------builder.aggregation(AggregationBuilders.extendedStats("agg").field("fee"));//---------------------------------------------request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 获取返回结果ExtendedStats agg = resp.getAggregations().get("agg");double max = agg.getMax();double min = agg.getMin();System.out.println("fee的最大值为:" + max + ",最小值为:" + min);
}

6.6 基于es的elasticsearch-rest-high-level-client包整合的地图经纬度搜索

ES中提供了一个数据类型 geo_point,这个类型就是用来存储经纬度的。

创建一个带geo_point类型的索引,并添加测试数据

# 创建一个索引,指定一个name,locaiton
PUT /map
{"settings": {"number_of_shards": 5,"number_of_replicas": 1},"mappings": {"map": {"properties": {"name": {"type": "text"},"location": {"type": "geo_point"}}}}
}# 添加测试数据
PUT /map/map/1
{"name": "天安门","location": {"lon": 116.403981,"lat": 39.914492 }
}PUT /map/map/2
{"name": "海淀公园","location": {"lon": 116.302509,"lat": 39.991152 }
}PUT /map/map/3
{"name": "北京动物园","location": {"lon": 116.343184,"lat": 39.947468 }
}
6.6.1 ES的地图检索方式
语法 说明
geo_distance 直线距离检索方式
geo_bounding_box 以两个点确定一个矩形,获取在矩形内的全部数据
geo_polygon 以多个点,确定一个多边形,获取多边形内的全部数据
6.6.2 基于RESTful实现地图检索

geo_distance

# geo_distance
POST /map/map/_search
{"query": {"geo_distance": {"location": {             # 确定一个点"lon": 116.433733,"lat": 39.908404},"distance": 3000,           # 确定半径"distance_type": "arc"     # 指定形状为圆形}}
}

geo_bounding_box

# geo_bounding_box
POST /map/map/_search
{"query": {"geo_bounding_box": {"location": {"top_left": {              # 左上角的坐标点"lon": 116.326943,"lat": 39.95499},"bottom_right": {          # 右下角的坐标点"lon": 116.433446,"lat": 39.908737}}}}
}

geo_polygon

# geo_polygon
POST /map/map/_search
{"query": {"geo_polygon": {"location": {"points": [                 # 指定多个点确定一个多边形{"lon": 116.298916,"lat": 39.99878},{"lon": 116.29561,"lat": 39.972576},{"lon": 116.327661,"lat": 39.984739}]}}}
}
6.6.3 Java实现geo_polygon
// 基于Java实现geo_polygon查询
@Test
public void geoPolygon() throws IOException {//1. SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定检索方式SearchSourceBuilder builder = new SearchSourceBuilder();List<GeoPoint> points = new ArrayList<>();points.add(new GeoPoint(39.99878,116.298916));points.add(new GeoPoint(39.972576,116.29561));points.add(new GeoPoint(39.984739,116.327661));builder.query(QueryBuilders.geoPolygonQuery("location",points));request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}

更多请参考:

API: https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.10.1/index.html

}

#### 6.6 基于es的elasticsearch-rest-high-level-client包整合的地图经纬度搜索> ES中提供了一个数据类型 geo_point,这个类型就是用来存储经纬度的。
>
> 创建一个带geo_point类型的索引,并添加测试数据```json
# 创建一个索引,指定一个name,locaiton
PUT /map
{"settings": {"number_of_shards": 5,"number_of_replicas": 1},"mappings": {"map": {"properties": {"name": {"type": "text"},"location": {"type": "geo_point"}}}}
}# 添加测试数据
PUT /map/map/1
{"name": "天安门","location": {"lon": 116.403981,"lat": 39.914492 }
}PUT /map/map/2
{"name": "海淀公园","location": {"lon": 116.302509,"lat": 39.991152 }
}PUT /map/map/3
{"name": "北京动物园","location": {"lon": 116.343184,"lat": 39.947468 }
}
6.6.1 ES的地图检索方式
语法 说明
geo_distance 直线距离检索方式
geo_bounding_box 以两个点确定一个矩形,获取在矩形内的全部数据
geo_polygon 以多个点,确定一个多边形,获取多边形内的全部数据
6.6.2 基于RESTful实现地图检索

geo_distance

# geo_distance
POST /map/map/_search
{"query": {"geo_distance": {"location": {             # 确定一个点"lon": 116.433733,"lat": 39.908404},"distance": 3000,           # 确定半径"distance_type": "arc"     # 指定形状为圆形}}
}

geo_bounding_box

# geo_bounding_box
POST /map/map/_search
{"query": {"geo_bounding_box": {"location": {"top_left": {              # 左上角的坐标点"lon": 116.326943,"lat": 39.95499},"bottom_right": {          # 右下角的坐标点"lon": 116.433446,"lat": 39.908737}}}}
}

geo_polygon

# geo_polygon
POST /map/map/_search
{"query": {"geo_polygon": {"location": {"points": [                 # 指定多个点确定一个多边形{"lon": 116.298916,"lat": 39.99878},{"lon": 116.29561,"lat": 39.972576},{"lon": 116.327661,"lat": 39.984739}]}}}
}
6.6.3 Java实现geo_polygon
// 基于Java实现geo_polygon查询
@Test
public void geoPolygon() throws IOException {//1. SearchRequestSearchRequest request = new SearchRequest(index);request.types(type);//2. 指定检索方式SearchSourceBuilder builder = new SearchSourceBuilder();List<GeoPoint> points = new ArrayList<>();points.add(new GeoPoint(39.99878,116.298916));points.add(new GeoPoint(39.972576,116.29561));points.add(new GeoPoint(39.984739,116.327661));builder.query(QueryBuilders.geoPolygonQuery("location",points));request.source(builder);//3. 执行查询SearchResponse resp = client.search(request, RequestOptions.DEFAULT);//4. 输出结果for (SearchHit hit : resp.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}
}

更多请参考:

API: https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.10.1/index.html

参考文档:https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.10.1/index.html

elasticsearch的使用相关推荐

  1. Elasticsearch学习之路(一)

    一.前序 1.1正向索引和倒排索引 ** 正向索引通常用于数据库中,在搜索引擎领域使用的最多的就是倒排索引 ** 通过例子表示: 我爱编程, 我爱编程,我是小码农 1.1.1 正向索引 假设我们使用m ...

  2. 2021年大数据ELK(二十五):添加Elasticsearch数据源

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 添加Elasticsearch数据源 一.Kibana索引模式 添加Elast ...

  3. 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 使用FileBeat采集Kafka日志到Elasticsearch 一.需求分 ...

  4. 2021年大数据ELK(十七):Elasticsearch SQL 订单统计分析案例

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 订单统计分析案例 一.案例介绍 二.创建索引 三.导入测试数据 四.统计不同支 ...

  5. 2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 职位查询案例 一.查询职位索引库中的一条数据 二.将SQL转换为DSL 三.职 ...

  6. 2021年大数据ELK(十五):Elasticsearch SQL简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch SQL简单介绍 一.SQL与Elasticsear ...

  7. 2021年大数据ELK(十三):Elasticsearch编程(添加职位数据)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch编程 一.添加职位数据 1.初始化客户端连接 2.实 ...

  8. 2021年大数据ELK(十二):Elasticsearch编程(环境准备)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch编程 一.环境准备 1.准备IDEA项目结构 2.准 ...

  9. 2021年大数据ELK(十一):Elasticsearch架构原理

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch架构原理 一.Elasticsearch的节点类型 ...

  10. 2021年大数据ELK(八):Elasticsearch安装IK分词器插件

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 安装IK分词器 一.下载Elasticsearch IK分词器 ...

最新文章

  1. 如何轻松阅读 GitHub 上的项目源码?
  2. pytroch一机多卡训练
  3. php操作MySQL
  4. string转object对象_025:听闻你精通面向对象,来解决一下
  5. C#操作IIS6创建网站应用程序无效
  6. PWN-PRACTICE-BUUCTF-11
  7. PL/SQL-FOR UPDATE 与 FOR UPDATE OF的区别
  8. python 3d绘图库_python – 用于科学3d绘图的Mayavi的替代品
  9. Windows下如何安装MySQL服务
  10. 纯Java代码 图片压缩
  11. EurekaLog发送邮件问题修正
  12. tdscdma手机linux,全方位介绍——TD-SCDMA无线技术(1)
  13. ERP系统与MRP系统
  14. 东西向流量/南北向流量
  15. [Vuetify] Multiple instances of Vue detected
  16. 系统崩溃分析 - vmcore 加载到 Trace32
  17. 老飞飞魅力飞飞关于攻击辅助研究带易语言源码视频教程
  18. 外贸邮箱服务器设置,外贸邮客户端设置方法?
  19. cad能自学成才吗_我在6个月内成为一名自学成才的开发人员,所以你能
  20. zigbee现存网络下更换协调器

热门文章

  1. FMDB的简单应用(4篇)
  2. mysql 进阶(二)
  3. eclipse pmd的使用
  4. 好问题:为什么有些大公司技术弱爆了?
  5. 光阑,像差和成像光学仪器
  6. 【MySQL】逻辑库与数据表相关操作
  7. 卡方检验(Chi square statistic)
  8. 国庆 深圳游玩 路线规划之南山区
  9. 爬虫|基于船讯网实现AIS数据爬虫 船讯网轨迹数据以及轨迹信息
  10. This page can't be displayed. Contact support for additional information. The incident ID is: xxxxxx