目录
Elaticsearch,简称为es, es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。ES使用Java开发。Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

- 百度:百度目前广泛使用Elasticsearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括casio、云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据
- 新浪使用ES 分析处理32亿条实时日志
- 阿里使用ES 构建挖财自己的日志采集和分析体系
- 2013年初,GitHub抛弃了Solr,采用Elasticsearch 来做PB级的搜索。 “GitHub使用Elasticsearch
- 搜索20TB的数据,包括13亿文件和1300亿行代码”
- 维基百科:启动以Elasticsearch为基础的核心搜索架构
- SoundCloud:“SoundCloud使用Elasticsearch为1.8亿用户提供即时而精准的音乐搜索服务”
企业使用场景一般分为2种情况:
1、在线运维系统:
模块搜索功能使用数据库查询实现,但是已经出现性能问题,或者不满足产品的高亮相关度排序需求
时。这种情况就会对系统的查询功能进行技术改造,转而使用全文检索,而es就是首选。改造业务流程
如图:

2、可插加式功能:
产品一开始就要实现高亮相关度排序等全文检索的功能。针对这种情况,企业实现功能业务流程如图:

3、索引库存的作用
索引库的数据是用来搜索用的,里面存储的数据和数据库一般不会是完全一样的,一般都比数据库的数
据少。
那索引库存什么数据呢?
以业务需求为准,需求决定页面要显示什么字段以及会按什么字段进行搜索,那么这些字段就都要保存
到索引库中。
1、ES下载
目前Elasticsearch最新的版本是7.4.2,我们使用6.8.0版本,建议使用JDK1.8及以上
Elasticsearch分为Linux和Window版本,基于我们主要学习的是Elasticsearch的Java客户端的使用,所
以我们课程中使用的是安装较为简便的Window版本,项目上线后,公司的运维人员会安装Linux版的
ES供我们连接使用。
Elasticsearch的官方地址:https://www.elastic.co/cn/downloads/past-releases
2、启动ES配置
Window版的Elasticsearch的安装很简单,类似Window版的Tomcat,解压开即安装完毕,解压后的
Elasticsearch的目录结构如下:

3、启动ES命令
点击Elasticsearch下的bin目录下的Elasticsearch.bat启动,控制台显示的日志信息如下:

注意:9300是tcp通讯端口,集群间和TCP 客户端都执行该端口,9200是http协议的RESTful接口 。
通过浏览器访问Elasticsearch服务器,看到如下返回的json信息,代表服务启动成功:

ElasticSearch6.8.0默认占用本机内存1个G,如果不足,建议改小一点。经测试125m足够开发测试使
用。
注意:Elasticsearch是使用java开发的,且本版本的es需要的jdk版本要是1.8及以上,所以安装
Elasticsearch之前保证JDK1.8+安装完毕,并正确的配置好JDK环境变量,否则启动Elasticsearch失败。
1. 在Chrome浏览器地址栏中输入:chrome://extensions/

2. 打开Chrome扩展程序的开发者模式
3. 将资料中的 ElasticSearch-head-Chrome插件.crx 拖入浏览器的插件页面:

4. 解压crx插件,通过加载已解压的扩展程序来加载

5. 最后即可安装成功

1、Kibana说明
Kibana是ElasticSearch的数据可视化和实时分析的工具,利用Elasticsearch的聚合功能,生成各种图
表,如柱形图,线状图,饼图等。
https://www.elastic.co/cn/products/kibana

2、安装配置
2.1 解压即安装成功

2.2 进入安装目录下的config目录的kibana.yml文件
修改elasticsearch服务器的地址:
修改kibana配置支持中文:
4、运行访问
4.1 进入安装目录下的bin目录
4.2 双击运行,启动成功:
elasticsearch.url: "http://localhost:9200"

i18n.locale: "zh-CN"



4.3 发现kibana的监听端口是5601,我们访问:http://127.0.0.1:5601

Lucene的IK分词器早在2012年已经没有维护了,现在我们要使用的是在其基础上维护升级的版本,并
且开发为Elasticsearch的集成插件了,与Elasticsearch一起维护升级,版本也保持一致。
GitHub仓库地址:https://github.com/medcl/elasticsearch-analysis-ik
下载插件:

1、安装插件
插件已经在资料中准备好了,解压之后,存放到D:\elasticsearch-6.8.0\plugins\目录中,即可安装成功
插件。
注意:解压的时候,如下文件必须在plugins目录的第一级目录下
重新启动ElasticSearch之后,看到如下日志代表安装成功

2、测试
IK分词器有两种分词模式:ik_max_word和ik_smart模式。
ik_max_word:会将文本做最细粒度的拆分
ik_smart:会做最粗粒度的拆分,智能拆分
最细粒度的拆分结果:

请求方式:POST
请求url:http://127.0.0.1:9200/_analyze
请求体:
{
"analyzer": "ik_smart",
"text": "南京市长江大桥"
} {
"tokens": [
{
"token": "南京市",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "南京",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 1
},
{
"token": "市长",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 2
},
{
"token": "市",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 3
},
{
"token": "长江大桥",
"start_offset": 3,
"end_offset": 7,
"type": "CN_WORD",
"position": 4
},
{
"token": "长江",
"start_offset": 3,
智能拆分结果:

3、添加扩展词典和停用词典
停用词:有些词在文本中出现的频率非常高。但对本文的语义产生不了多大的影响。例如英文的a、
an、the、of等。或中文的”的、了、呢等”。这样的词称为停用词。停用词经常被过滤掉,不会被进行
索引。在检索的过程中,如果用户的查询词中含有停用词,系统会自动过滤掉。停用词可以加快索引的
速度,减少索引库文件的大小。
扩展词:就是不想让哪些词被分开,让他们分成一个词。比如上面的江大桥
南京市长江大桥
南京市,长江大桥
南京,市长,江大桥
江大桥拆分出来,
"end_offset": 5,
"type": "CN_WORD",
"position": 5
},
{
"token": "大桥",
"start_offset": 5,
"end_offset": 7,
"type": "CN_WORD",
"position": 6
}
]
} {
"tokens": [
{
"token": "南京市",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "长江大桥",
"start_offset": 3,
"end_offset": 7,
"type": "CN_WORD",
"position": 1
}
]
}
自定义扩展词库
1. 进入到D:\elasticsearch-6.8.0\plugins\elasticsearch-analysis-ik-6.8.0\config目录下, 新增自定义
词典myext_dict.dic
输入 :江大桥
2. 将我们自定义的扩展词典文件,配置到IKAnalyzer.cfg.xml文件中
3. 然后重启:
4. 进行测试:
{
"tokens": [
{
"token": "南京市",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
核心内容
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。
然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对
文档(而非成行成列的数据)进行索引、搜索、排序、过滤。Elasticsearch比传统关系型数据库如下:
详细说明:
"position": 0
},
{
"token": "市长",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 1
},
{
"token": "江大桥",
"start_offset": 5,
"end_offset": 8,
"type": "CN_WORD",
"position": 2
}
]
}
索引库(indexes) <-------------> 数据库(Databases)
类型(type) <------------------> 数据表(Table)
文档(Document) <--------------> 行(Row)
字段(Field) <-----------------> 列(Columns)
映射(mappings) <--------------> DDL创建数据库表的语句
| 概念 | 说明 |
| 索引库 | 索引库包含一堆相关业务,结构相似的文档document数据,比如说建立一个 |
| 类型(type) | type是索引库中的一个逻辑数据分类,一个type下的document,都有相同的 |
| 文档 | 文档是es中的存入索引库最小数据单元,一个document可以是一条客户数 |
| 字段(field) | Field是Elasticsearch的最小单位。一个document里面有多个field,每个field |
| 映射配置 | 对type文档结构的约束叫做 映射(mapping) ,用来定义document的每个字段 |
说明文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
实际开发中,有几种方式操作Elasticsearch服务:
第一类:发送http请求(RESTful风格)操作:9200端口
使用Postman发送请求直接操作。
使用ElasticSearch-head-master图形化界面插件操作
使用Elastic官方数据可视化的平台Kibana进行操作
第二类:通过Java代码操作:9300端口
Elasticsearch提供的Java API 客户端进行操作。

关系型数据库
新增数据库(show databases;)
删除数据库
新增表,删除表,查询表(show tables;)
文档的增删改查,分页查询,排序...
Elasticsearch采用Rest风格API,因此其API就是一次http请求,你可以用任何工具发起http请求
1.创建索引库
发送请求:
响应结果:
"acknowledged" : true, 代表操作成功 "shards_acknowledged" : true, 代表分片操作成功 "index" :
"jeflee" 表示创建的索引库名称
注意:创建索引库的分片数默认5片,在7.0.0之后的ElasticSearch版本中,默认分片数变为1片;
2.查看索引库
发送请求:
# 在kibana中,不用写地址和端口,/jeflee是简化写法,真实请求地址是:
http://127.0.0.1:9200/jeflee
# 请求方法:PUT
PUT /jeflee
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "jeflee"
} #
请求方法GET
GET /jeflee

响应结果:**
响应内容解释:
{
"jeflee" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"creation_date" : "1573610302775",
"number_of_shards" : "5",
"number_of_replicas" : "1",
"uuid" : "6Ffe20CIT76KchAcvqE6NA",
"version" : {
"created" : "6080099"
},
"provided_name" : "jeflee"
}
}
}
} {
"jeflee【索引库名】" : {
"aliases【别名】" : { },
"mappings【映射】" : { },
"settings【索引库设置】" : {
"index【索引】" : {
"creation_date【创建时间】" : "1573610302775",
"number_of_shards【索引库分片数】" : "5",
"number_of_replicas【索引库副本数】" : "1",
"uuid【唯一标识】" : "6Ffe20CIT76KchAcvqE6NA",
"version【版本】" : {
"created" : "6080099"
},
"provided_name【索引库名称】" : "jeflee"
}
}
}
}
3.删除索引库
发送请求:
响应结果
有了 索引库 ,等于有了数据库中的 database 。接下来就需要索引库中的 类型 了,也就是数据库中的
表 。创建数据库表需要设置字段约束,索引库也一样,在创建索引库的类型时,需要知道这个类型下
有哪些字段,每个字段有哪些约束信息,这就叫做 映射(mapping)
1.配置映射
给jeflee这个索引库添加了一个名为 goods 的类型,并且在类型中设置了4个字段:
title:商品标题
subtitle: 商品子标题
images:商品图片
price:商品价格
发送请求:
# 请求方法:DELETE
DELETE /jeflee
{
"acknowledged" : true
} P
UT /jeflee/goods/_mapping
{
"properties": {
"title":{
"type": "text",
"analyzer": "ik_max_word"
},
"subtitle":{
"type": "text",
"analyzer": "ik_max_word"
},
"images":{
"type": "keyword",
"index": false
},
"price":{
"type": "float",
"index": true
}
}
}
响应结果:

内容解释:
类型名称:就是前面将的type的概念,类似于数据库中的表 字段名:任意填写,下面指定许多属性,例
如:
type:类型,Elasticsearch中支持的数据类型非常丰富,说几个关键的:
1. String类型,又分两种:
text:可分词
keyword:不可分词,数据会作为完整字段进行匹配
2. Numerical:数值类型,分两类
基本数据类型:long、interger、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
3. Date:日期类型
4. Array:数组类型
5. Object:对象
index:是否索引,默认为true,也就是说你不进行任何配置,所有字段都会被索引。
true:字段会被索引,则可以用来进行搜索。默认值就是true
false:字段不会被索引,不能用来搜索
store:是否将数据进行独立存储,默认为false
原始的文本会存储在 _source 里面,默认情况下其他提取出来的字段都不是独立存储的,是
从 _source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置store:true即
{
"acknowledged" : true
} P
UT /索引库名/_mapping/类型名称 或 索引库名/类型名称/_mapping
{
"properties": {
"字段名称":{
"type【类型】": "类型",
"index【是否索引】": true,
"store【是否存储】": true,
"analyzer【分析器】": "分词器"
} .
..
}
}
可,获取独立存储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根
据实际业务需求来设置,默认为false。
analyzer:分词器,这里的 ik_max_word 即使用ik分词器
2.查看映射
发送请求:
响应结果:
3.一次创建索引库及配置映射(常用)
刚才的案例中,我们是把创建索引库和类型分开来做,其实也可以在创建索引库的同时,直接制定索引
库中的类型
发送请求:
# 请求方法:GET
GET /jeflee/goods/_mapping
{
"jeflee" : {
"mappings" : {
"goods" : {
"properties" : {
"images" : {
"type" : "keyword",
"index" : false
},
"price" : {
"type" : "float"
},
"subtitle" : {
"type" : "text",
"analyzer" : "ik_max_word"
},
"title" : {
"type" : "text",
"analyzer" : "ik_max_word"
}}}}}
} P
UT /jeflee1
{
"settings": {},
"mappings": {
"goods":{
"properties": {
"title":{
"type": "text",
"analyzer": "ik_max_word"
},
"subtitle":{
"type": "text",
响应结果:
请求内容解释:
3.3 文档操作
文档,即索引库中某个类型下的数据,会根据规则创建索引,将来用来搜索。可以类比做数据库中的每
一行数据。
1.新增文档
发送请求:
"analyzer": "ik_max_word"
},
"images":{
"type": "keyword",
"index": false
},
"price":{
"type": "float",
"index": true
}
}
}
}
} {
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "jeflee1"
} P
UT /{索引库名称}
{
"settings【设置】": {},
"mappings【映射】": {
"{类型名称}":{
"properties": {
"title":{
"type【类型】": "text",
"index【是否索引】": true,
"store【是否存储】": true,
"analyzer【分析器】": "ik_max_word"
} .
..
}
}
}
}
响应结果:
响应结果解析:
可以看到结果显示为: created ,是创建成功了。
另外,需要注意的是,在响应结果中有个 _id 字段,这个就是这条文档数据的 唯一标示 ,以后的增删改
查都依赖这个id作为唯一标示。可以看到id的值为:EwVLY24BL4R5dXuhZ--1,这里我们新增时没有指
定id,所以是ES帮我们随机生成的id。
2.查看文档
根据rest风格,新增是put,查询是get(post也可以用来做查询),不过查询一般都需要条件,这里我们
把刚刚生成数据的id带上。
发送请求:
POST /jeflee/goods
{
"title":"小米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":2699.00
} {
"_index" : "jeflee",
"_type" : "goods",
"_id" : "EwVLY24BL4R5dXuhZ--1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
} {
"_index【索引库】" : "jeflee",
"_type【类型】" : "goods",
"_id【主键id】" : "EwVLY24BL4R5dXuhZ--1",
"_version【版本】" : 1,
"result【操作结果】" : "created",
"_shards【分片】" : {
"total【总数】" : 2,
"successful【成功】" : 1,
"failed【失败】" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
} G
ET /jeflee/goods/EwVLY24BL4R5dXuhZ--1
响应结果:
响应结果解析:
_source :源文档信息,所有的数据都在里面。
_id :这条文档的唯一标示
found:查询结果,返回true代表查到,false代表没有
3.自定义id新增文档
发送请求:
响应结果:
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "EwVLY24BL4R5dXuhZ--1",
"_version" : 1,
"
_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699.0
}
} {
"_index【索引库】" : "jeflee",
"_type【类型】" : "goods",
"_id【主键id】" : "EwVLY24BL4R5dXuhZ--1",
"_version【版本】" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found【查询结果】" : true,
"_source【源文档信息】" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699.0
}
} P
OST /jeflee/goods/1
{
"title":"小米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":2699.00
} {
"_index" : "jeflee",
"_type" : "goods",
"_id" : "1",
主键id变为指定的id
请求内容解析:
4.修改文档
新增时,主键不变则会将原有内容覆盖。
发送请求:
响应结果:
可以看到result结果是: updated ,显然是更新数据
5.删除文档
"
_version" : 1,
"result" : "created",
"
_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
} P
OST /jeflee/goods/{自定义注解id}
{
"title":"小米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":2699.00
} P
OST /jeflee/goods/1
{
"title":"超米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":3899.00
} {
"_index" : "jeflee",
"_type" : "goods",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
1、删除一条
删除一个文档也不会立即从磁盘上移除,它只是被标记成已删除。Elasticsearch将会在你之后添加更多
索引的时候才会在后台进行删除内容的清理。
发送请求:
响应结果:
可以看到result结果是:deleted,数据被删除。如果删除不存在的问题,result:not_found
2、根据条件删除:
发送请求:
响应结果:
DELETE /jeflee/goods/1
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
} P
OST /jeflee/_delete_by_query
{
"query":{
"match":{
"title":"小米"
}
}
} {
"took" : 58,
"timed_out" : false,
响应结果解析:
6.发送请求批量操作_bulk
Bulk 操作是将文档的增删改查一些列操作,通过一次请求全都做完。减少网络传输次数。相当于,将多
个新增、修改、删除的请求写到一次请求当中。
注意:bulk的请求体与其他的请求体稍有不同!
请求语法:
语法解析:
每行一定要以换行符(\n)结尾,包括最后一行
action/metadata 部分,指定做什么操作
action代表操作的动作,必须是如下的动作之一
"total" : 2,
"deleted" : 2,
"batches" : 1,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"requests_per_second" : -1.0,
"throttled_until_millis" : 0,
"failures" : [ ]
} {
"took【耗时】" : 58,
"timed_out" : false,
"total【总数】" : 2,
"deleted【删除总数】" : 2,
"batches" : 1,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"requests_per_second" : -1.0,
"throttled_until_millis" : 0,
"failures" : [ ]
} P
OST /jeflee/goods/_bulk
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
create:如果文档不存在,那么就创建
index:创建一个新的文档或者替换现有文档
update:部分更新文档
delete:删除一个文档,这种操作不带请求体
metadata,是文档的元数据,包括索引( _index ),类型( _type ),id( _id )...等
request body 请求体,正常的新增文档的请求体内容(注意,不要带换行符)
隔离:每个操作互不影响。操作失败的行会返回其失败信息。
实际用法:bulk请求一次不要太大,否则积压到内存中,性能会下降。所以,一次请求几千个操作、大
小控制在5M-15M之间正好。
发送请求:
注意:
请求体的内容不要换行
请注意 delete 动作不能有请求体
谨记最后一个换行符不要落下。
响应结果:
POST /jeflee/goods/_bulk
{"index":{"_index" : "jeflee","_type" : "goods"}}
{"title":"大米手机","images":"http://image.leyou.com/12479122.jpg","price":3288}
{"index":{"_index" : "jeflee","_type" : "goods"}}
{"title":"小米手机","images":"http://image.leyou.com/12479122.jpg","price":2699}
{"index":{"_index" : "jeflee","_type" : "goods"}}
{"title":"小米电视
4A","images":"http://image.leyou.com/12479122.jpg","price":4288}
{"index":{"_index" : "jeflee","_type" : "goods"}}
{"title": "华为手机","images": "http://image.leyou.com/12479122.jpg","price":
5288,"subtitle": "小米"}
{"index":{"_index" : "jeflee","_type" : "goods"}}
{"title":"apple手
机","images":"http://image.leyou.com/12479122.jpg","price":5899.00}
{
"took" : 41,
"errors" : false,
"items" : [
{
"index" : {
"_index" : "jeflee",
"_type" : "goods",
"_id" : "FFTEhm4BO0vjk-su75eC",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
每个子请求都是独立执行,因此某个子请求的失败不会对其他子请求的成功与否造成影响。 如果其中任
何子请求失败,最顶层的 error 标志被设置为 true ,并且在相应的请求报告出错误明细。
status属性:代表响应状态码
Elasticsearch提供了一个基于JSON的,在请求体内编写查询语句的查询方式。称之为请求体查询。
Elasticsearch 使用它以简单的 JSON接口来展现 Lucene 功能的绝大部分。这种查询语言相对于使用晦
涩难懂的查询字符串的方式,更灵活、更精确、易读和易调试。
这种查询还有一种称呼:Query DSL (Query Domain Specific Language),领域特定语言。
1、查询所有(match_all)
发送请求:
请求内容解析:
这里的query代表一个查询对象,里面可以有不同的查询属性
查询类型:
例如: match_all(代表查询所有) , match , term , range 等等
查询条件:查询条件会根据类型的不同,写法也有差异
响应结果
}
} .
..
]
} P
OST /jeflee/_search
{
"query": {
"match_all": {}
}
} 请
求方法:POST
请求地址:http://127.0.0.1:9200/索引库名/_search
POST /{索引库}/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}
响应结果解析:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "ADWoZ24Bx8DA1HO-R9DD",
"_score" : 1.0,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "_zWoZ24Bx8DA1HO-R8_D",
"_score" : 1.0,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "_jWoZ24Bx8DA1HO-R8_D",
"_score" : 1.0,
"_source" : {
"title" : "大米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 3288
}}]}}
{
"took【查询花费时间,单位毫秒】" : 1,
"timed_out【是否超时】" : false,
"_shards【分片信息】" : {
"total【总数】" : 5,
"successful【成功】" : 5,
"skipped【忽略】" : 0,
"failed【失败】" : 0
},
2、匹配查询(match)
match 类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系
发送请求:
响应结果:
"hits【搜索命中结果】" : {
"total【命中总数】" : 3,
"max_score【所有查询结果中,文档的最高得分】" : 1.0,
"hits【命中结果集合】" : [
{
"_index【索引库】" : "jeflee",
"_type【类型】" : "goods",
"_id【主键】" : "ADWoZ24Bx8DA1HO-R9DD",
"_score【当前结果匹配得分】" : 1.0,
"_source【源文档信息】" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
}...}]}}
POST /jeflee/_search
{
"query": {
"match": {
"title": "小米手机"
}
}
} {
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.5753642,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "_zWoZ24Bx8DA1HO-R8_D",
"_score" : 0.5753642,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
在上面的案例中,不仅会查询到电视,而且与小米相关的都会查询到。某些情况下,我们需要更精确查
找,我们希望这个关系变成 and ,可以这样做:
发送请求:
本例中,只有同时包含 小米 和 手机 的词条才会被搜索到。
响应结果:
},
{
"
_index" : "jeflee",
"_type" : "goods",
"_id" : "ADWoZ24Bx8DA1HO-R9DD",
"_score" : 0.2876821,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "_jWoZ24Bx8DA1HO-R8_D",
"_score" : 0.2876821,
"_source" : {
"title" : "大米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 3288
}
}
]
}
} P
OST /jeflee/_search
{
"query": {
"match": {
"title": {
"query": "小米手机",
"operator": "and"
}
}
}
} {
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
3、多字段匹配查询(multi_match)
multi_match 与 match 类似,不同的是它可以在多个字段中查询。
发送请求:
本例中,我们在title字段和subtitle字段中查询 小米 这个词
fields属性:设置查询的多个字段
响应结果:
"hits" : {
"total" : 1,
"max_score" : 0.5753642,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "_zWoZ24Bx8DA1HO-R8_D",
"_score" : 0.5753642,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
}
]
}
} P
OST /jeflee/_search
{
"query": {
"multi_match": {
"query": "小米",
"fields": ["title","subtitle"]
}
}
} {
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0.6099695,
"hits": [
{
"_index": "jeflee",
"_type": "goods",
4、关键词精确查询(term)
term查询,精确的关键词匹配查询,不对象查询条件进行分词
发送请求:
响应结果:
"_id": "qfHnLG4BWrjRrOzL8Ywa",
"
_score": 0.6099695,
"_source": {
"title": "小米电视4A",
"images": "http://image.leyou.com/12479122.jpg",
"price": 4288
}
},
{
"
_index": "jeflee",
"_type": "goods",
"_id": "qvHyLG4BWrjRrOzL9Yzn",
"_score": 0.2876821,
"_source": {
"title": "华为手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 5288,
"subtitle": "小米"
}
},
{
"_index": "jeflee",
"_type": "goods",
"_id": "qPHnLG4BWrjRrOzL3Yxl",
"_score": 0.2876821,
"_source": {
"title": "小米手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 2699
}
}
]
}
} P
OST /jeflee/_search
{
"query": {
"term": {
"title": {
"value": "小米"
}
}
}
} {
"took" : 0,
5、多关键词精确查询(terms)
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一
个值,那么这个文档满足条件,类似于mysql的in:
发送请求:
查询价格为2699或4288的商品
响应结果:
"timed_out" : false,
"
_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CzXDZ24Bx8DA1HO-nNDZ",
"_score" : 0.6931472,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "DDXDZ24Bx8DA1HO-nNDZ",
"_score" : 0.2876821,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
}
]
}
} P
OST /jeflee/_search
{
"query": {
"terms": {
"price": [2699,4288]
}
}
}
默认情况下,elasticsearch在搜索的结果中,会把文档中保存在 _source 的所有字段都返回。如果我们
只想获取其中的部分字段,我们可以添加 _source 的过滤
1、指定字段
指定查询结果中,只显示title和price两个字段
发送请求:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CzXDZ24Bx8DA1HO-nNDZ",
"_score" : 0.6931472,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "DDXDZ24Bx8DA1HO-nNDZ",
"_score" : 0.2876821,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
}
]
}
}
2、过滤指定字段:includes和excludes
我们也可以通过:
includes:来指定想要显示的字段
excludes:来指定不想要显示的字段
二者都是可选的。
发送请求:
1、布尔组合(bool)
POST /jeflee/_search
{
"_source": ["title","price"],
"query": {
"term": {
"price": 2699
}
}
} P
OST /jeflee/_search
{
"_source": {
"includes":["title","price"]
},
"query": {
"term": {
"price": 2699
}
}
} P
OST /jeflee/_search
{
"_source": {
"excludes": ["images"]
},
"query": {
"term": {
"price": 2699
}
}
}
bool 把各种其它查询通过 must (必须 )、 must_not (必须不)、 should (应该)的方式进行组合
发送请求:
响应结果:
2、范围查询(range)
range 查询找出那些落在指定区间内的数字或者时间。 range 查询允许以下字符:
post /jeflee/_search
{
"query":{
"bool":{
| "must": | { "match": { "title": "小米" }}, |
| "must_not": { "match": { "title": | "电视" }}, |
| "should": | { "match": { "title": "手机" }} |
}
}
} {
"took": 11,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5753642,
"hits": [
{
"_index": "jeflee",
"_type": "goods",
"_id": "qPHnLG4BWrjRrOzL3Yxl",
"_score": 0.5753642,
"_source": {
"title": "小米手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 2699
}
}
]
}
}
| 操作符 | 说明 |
| gt == (greater than) | 大于> |
| gte == (greater than equal) | 大于等于>= |
| lt == (less than) | 小于< |
| lte == (less than equal) | 小于等于<= |
发送请求:
查询价格大于等于2699,且小于4000元的所有商品。
响应结果:
POST /jeflee/_search
{
"query": {
"range": {
"price": {"gte": 2699,"lt": 4000}
}
}
} {
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CjXDZ24Bx8DA1HO-nNDZ",
"_score" : 1.0,
"_source" : {
"title" : "大米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 3288
}
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CzXDZ24Bx8DA1HO-nNDZ",
"_score" : 1.0,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
3、模糊查询(fuzzy)
fuzzy自动将拼写错误的搜索文本,进行纠正,纠正以后去尝试匹配索引中的数据。它允许用户搜索词
条与实际词条出现偏差,但是偏差的编辑距离不得超过2:
发送请求:
如下查询,也能查询到apple手机
修改偏差值:
你搜索关键词的偏差,默认就是2,我们可以通过fuzziness修改。
1、单字段排序
sort 可以让我们按照不同的字段进行排序,并且通过 order 指定排序的方式。desc降序,asc升序。
发送请求:
"price" : 2699
}
}
]
}
} P
OST /jeflee/_search
{
"query": {
"fuzzy": {
"title": "appla"
}
}
} P
OST /jeflee/_search
{
"query": {
"fuzzy": {
"title": {
"value": "applaa",
"fuzziness": 2
}
}
}
}
响应结果:
POST /jeflee/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": {"order": "desc"}
}
]
} {
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : null,
"hits" : [
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "DjXDZ24Bx8DA1HO-nNDZ",
"_score" : null,
"_source" : {
"title" : "apple手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 5899.0
},
"sort" : [
5899.0
]
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "DTXDZ24Bx8DA1HO-nNDZ",
"_score" : null,
"_source" : {
"title" : "华为手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 5288,
"subtitle" : "小米"
},
"sort" : [
5288.0
]
},
2、多字段排序
假定我们想要结合使用 price和 _score(得分) 进行查询,并且匹配的结果首先按照价格排序,然后按
照相关性得分排序:
发送请求:
{
"
_index" : "jeflee",
"
_type" : "goods",
"_id" : "DDXDZ24Bx8DA1HO-nNDZ",
"_score" : null,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
},
"sort" : [
4288.0
]
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CjXDZ24Bx8DA1HO-nNDZ",
"_score" : null,
"_source" : {
"title" : "大米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 3288
},
"sort" : [
3288.0
]
},
{
"_index" : "jeflee",
"_type" : "goods",
"_id" : "CzXDZ24Bx8DA1HO-nNDZ",
"_score" : null,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
},
"sort" : [
2699.0
]
}
]
}
}
发送请求:
size:每页显示多少条
from:当前页的起始索引,int from = (当前页 - 1) * 每页条数
POST /jeflee/_search
{
"query":{
"match_all":{}
},
"sort": [
{ "price": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
} P
OST /jeflee/_search
{
"query": {
"match_all": {}
},
"size": 2,
"from": 0
}
Spring Boot集成Elasticsearch的时候,我们需要引入高阶客户端【elasticsearch-rest-high-levelclient】【elasticsearch-rest-client】和【elasticsearch】来操作Elasticsearch,在引入起步依赖的时
候,需要严格注意Elasticsearch和起步依赖的版本关系,否则在使用过程中会出很多问题
搭建步骤:
1. 创建SpringBoot的项目,勾选starter配置
2. 配置Maven依赖坐标
3. 将ElasticSearch的客户端对象,注入Spring的容器
4. 配置ElasticSearch,服务地址,端口号
1、新增索引库
配置过程:
1. 创建SpringBoot的项目,勾选starter配置
选spring Initializr
配置项目信息
勾选starter,开发者工具、Lombok、配置文件映射处理器
2. 配置Maven依赖坐标
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.0</version>
</dependency>
<!--elasticsearch的rest客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.8.0</version>
</dependency>
<!--elasticsearch的核心jar包-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.0</version>
</dependency>
<!--elasticsearch的高级别rest客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
3. 将ElasticSearch的客户端对象,注入Spring的容器
4. 配置ElasticSearch,服务地址,端口号
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
@Component
public class ElasticSearchConfig {
private String host;
private Integer port;
//初始化RestHighLevelClient
@Bean(destroyMethod = "close")
public RestHighLevelClient client() {
//RestClient客户端构建器对象
RestClientBuilder restClientBuilder = RestClient.builder(new
HttpHost(host, port, "http"));
//操作es的高级rest客户端对象
RestHighLevelClient restHighLevelClient = new
RestHighLevelClient(restClientBuilder);
return restHighLevelClient;
} /
/getter ,setter,toString..省略
} #
es服务地址
elasticsearch.host=127.0.0.1
# es服务端口
elasticsearch.port=9200
# 配置日志级别,开启debug日志
logging.level.com.itheima=debug
目标:使用ElasticSearch的高阶客户端,编写Java代码,创建索引库
分析:
Java high level客户端的操作,是模仿我们通过发送请求调用RESTful接口调用的方式,本质还是请求获
取响应。
执行
发送请求中,传入请求对象的同时还设置了一个RequestOptions对象的静态成员变量DEFAULT。其含
义是,配置当前请求选项为默认值。
其中RequestOptions对象的作用是用来配置请求,主要配置项目有请求头,缓冲区大小(默认100M),
异常处理器(warningsHandler)。默认情况下,缓冲区大小100MB,请求头及异常处理器为空。
2、查看索引库
/**
* 索引库操作:
* 1.创建索引库
* 2.查询索引库
* 3.删除索引库
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo01IndexOperation {
//注入ES客户端对象
@Autowired
private RestHighLevelClient client;
/**
* 目标:创建索引库
* 1.创建请求对象
* 设置索引库name
* 2.客户端发送请求,获取响应对象
* 3.打印响应对象中的返回结果
* 4.关闭客户端,释放连接资源
*/
@Test
public void create() throws IOException {
//1.创建请求对象,创建索引的请求
CreateIndexRequest request = new CreateIndexRequest("heima3");
//2.客户端发送请求,获取响应对象
CreateIndexResponse response = client.indices().create(request,
RequestOptions.DEFAULT);
//3.打印响应对象中的返回结果
//返回index信息
System.out.println("index:"+response.index());
//acknowledged代表创建成功
System.out.println("acknowledged:"+response.isAcknowledged());
//4.关闭客户端,释放连接资源
client.close();
}
} /
**
* 查询索引
* 1.创建请求对象:查看索引库
执行
3、删除索引库
执行
* 设置索引库name
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
* 4.关闭客户端,释放连接资源
*/
@Test
public void getIndex() throws IOException {
//1.创建请求对象:查看索引库
GetIndexRequest request = new GetIndexRequest("heima4");
//2.客户端发送请求,获取响应对象
GetIndexResponse response = client.indices().get(request,
RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("aliases: "+response.getAliases());
System.out.println("settings: "+response.getSettings());
System.out.println("mappings: "+response.getMappings());
//4.关闭客户端,释放连接资源
client.close();
} /
**
* 删除索引
* 1.创建请求对象:删除索引库
* 设置索引库name
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
* 4.关闭客户端,释放连接资源
*/
@Test
public void delete() throws IOException {
//1.创建请求对象:删除索引库
DeleteIndexRequest request = new DeleteIndexRequest("heima2");
//2.客户端发送请求,获取响应对象
AcknowledgedResponse response = client.indices().delete(request,
RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("acknowledged::"+response.isAcknowledged());
//4.关闭客户端,释放连接资源
client.close();
}
当配置Spring的ioc容器中的RestHighLevelClient对象的销毁执行方法之后,每次容器销毁对象时,必
然会执行close方法,所以我们在使用完对象,可以不用每次手动关闭客户端。

1、配置映射
RestHighLevelClient配置映射,与kibana略有区别。在客户端中配置映射,不支持设置类型type。不
设置type,并不代表没有,而是默认的type为 _doc 。
/**
* 映射操作:
* 1.配置映射,一共2种方式:
* 第一种:使用XContentBuilder,构建请求体
* 第二种:使用JSON字符串
* 2.查看映射配置
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo02MappingOperation {
//注入ES客户端对象
@Autowired
private RestHighLevelClient client;
/**
*目标:配置映射。第一种方式,使用XContentBuilder,构建请求体
* 1.创建请求对象:配置映射
* 设置索引库name
* 设置配置映射请求体
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void putMappingMethodOne() throws IOException {
//1.创建请求对象:配置映射
PutMappingRequest request = new PutMappingRequest("heima4");
//构建请求体
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
jsonBuilder.startObject()
.startObject("properties")
.startObject("title")
.field("type","text").field("analyzer","ik_max_word")
.endObject()
.startObject("subtitle")
.field("type","text").field("analyzer","ik_max_word")
.endObject()
.startObject("category")
.field("type","keyword")
.endObject()
.startObject("brand")
.field("type","keyword")
.endObject()
.startObject("images")
执行
第二种方式:
执行
2、查看映射
.field("type","keyword").field("index",false)
.endObject()
.startObject("price")
.field("type","float")
.endObject()
.endObject()
.endObject();
//设置请求体,source("请求体json构建器对象");
request.source(jsonBuilder);
//2.客户端发送请求,获取响应对象
AcknowledgedResponse response = client.indices().putMapping(request,
RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("acknowledged::"+response.isAcknowledged());
}
} /
**
*目标:配置映射。第二种方式,使用JSON字符串
* 1.创建请求对象:配置映射
* 设置索引库name
* 设置配置映射请求体
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void putMappingMethodTwo() throws IOException {
//1.创建请求对象:配置映射
PutMappingRequest request = new PutMappingRequest("heima5");
//设置请求体,source("请求体json字符串","请求体的数据类型");
request.source("{\"properties\":{\"title\":
{\"type\":\"text\",\"analyzer\":\"ik_max_word\"},\"subtitle\":
{\"type\":\"text\",\"analyzer\":\"ik_max_word\"},\"category\":
{\"type\":\"keyword\"},\"brand\":{\"type\":\"keyword\"},\"price\":
{\"type\":\"float\"},\"images\":{\"type\":\"keyword\",\"index\":false}}}",
XContentType.JSON);
//2.客户端发送请求,获取响应对象
AcknowledgedResponse response = client.indices().putMapping(request,
RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("acknowledged::"+response.isAcknowledged());
} /
**
* 查看映射
* 1.创建请求对象:查看映射
* 设置索引库name
* 2.客户端发送请求,获取响应对象
执行
1、创建文档
创建实体:
创建操作代码:
* 3.打印响应结果
*/
@Test
public void getMapping() throws IOException {
//1.创建请求对象:查看映射
GetMappingsRequest request = new GetMappingsRequest();
//设置索引库name
request.indices("heima4");
//2.客户端发送请求,获取响应对象
GetMappingsResponse response = client.indices().getMapping(request,
RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("mappings::"+response.mappings());
System.out.println("Source::"+response.mappings().get("heima4").getSourceAsMap()
);
} p
ublic class Goods {
private Long id;//商品的唯一标识
private String title;//标题
private String subtitle;//子标题
private String category;//分类
private String brand;//品牌
private Double price;//价格
private String images;//图片地址
//...getter , setter , toString
} /
**
* 文档操作:
* 1.新增文档
* 2.根据id查询文档
* 3.修改文档
* 4.删除文档
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo03DocumentOperation {
//注入ES客户端对象
@Autowired
private RestHighLevelClient client;
/**
* 目标:新增文档
* 1.创建请求对象:新增文档
* 设置索引库name
执行
不设置主键ID
2、修改文档
主键id相同,修改数据
* 设置类型type
* 设置主键id,不设置随机生成
* 设置请求体
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void createDoc() throws IOException {
//1.创建请求对象:新增文档
IndexRequest request = new IndexRequest();
//设置索引库名称
request.index("heima4");
//设置type类型
request.type("_doc");
//设置主键id
request.id("1");
//构造Goods对象
Goods good = new Goods(1l,"小米手机","小米","手机","小
米",19999.0,"http://image.leyou.com/12479122.jpg");
//对象转json
String goodJsonStr = new ObjectMapper().writeValueAsString(good);
//设置请求体.source("json请求字符串","请求体的数据类型");
request.source(goodJsonStr,XContentType.JSON);
//2.客户端发送请求,获取响应对象
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("_index::"+response.getIndex());
System.out.println("_type::"+response.getType());
System.out.println("_id::"+response.getId());
System.out.println("result::"+response.getResult());
}
} /
**
* 修改文档
* 1.创建请求对象:修改文档
* 设置索引库name
* 设置类型type
* 设置主键id,必须设置
* 设置请求体
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void updateDoc() throws IOException {
//1.创建请求对象:修改文档
UpdateRequest request = new UpdateRequest();
//设置索引库名称
request.index("heima4");
执行
3、根据id查询文档
执行
4、删除文档
//设置type类型
request.type("_doc");
//设置主键id
request.id("1");
//构造Goods对象
Goods good = new Goods(1l,"大米手机","炒米","手机","小
米",999.0,"http://image.leyou.com/12479122.jpg");
//对象转json
String goodJsonStr = new ObjectMapper().writeValueAsString(good);
//设置请求体.source("json请求字符串","请求体的数据类型");
request.doc(goodJsonStr,XContentType.JSON);
//2.客户端发送请求,获取响应对象
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("_index::"+response.getIndex());
System.out.println("_type::"+response.getType());
System.out.println("_id::"+response.getId());
System.out.println("result::"+response.getResult());
} /
**
* 根据id查询文档
* 1.创建请求对象:根据id查询文档
* 设置索引库name
* 设置类型type
* 设置主键id
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void getDoc() throws IOException {
//1.创建请求对象:根据id查询文档
GetRequest request = new GetRequest();
//设置索引库name
request.index("heima4");
//设置类型type
request.type("_doc");
//设置主键id
request.id("1");
//2.客户端发送请求,获取响应对象
GetResponse response = client.get(request, RequestOptions.DEFAULT);
//3.打印响应结果
//3.打印响应结果
System.out.println("_index::"+response.getIndex());
System.out.println("_type::"+response.getType());
System.out.println("_id::"+response.getId());
System.out.println("_source::"+response.getSourceAsString());
}
执行
5、批量操作bulk
/**
* 删除文档
* 1.创建请求对象:删除文档
* 设置索引库name
* 设置类型type
* 设置主键id
* 2.客户端发送请求,获取响应对象
* 3.打印响应结果
*/
@Test
public void deleteDoc() throws IOException {
//1.创建请求对象:删除文档
DeleteRequest request = new DeleteRequest();
request.index("heima4");
request.id("1");
request.type("_doc");
//2.客户端发送请求,获取响应对象
DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
//3.打印响应结果
System.out.println("_index::"+response.getIndex());
System.out.println("_type::"+response.getType());
System.out.println("_id::"+response.getId());
System.out.println("_result::"+response.getResult());
} /
**
* 批量操作
* 1.批量新增
* 2.批量删除
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo04BulkOperation {
//注入ES客户端对象
@Autowired
private RestHighLevelClient client;
/**
* 目标:批量新增
* 1.创建请求对象:批量操作
* 2.批量操作中设置多个新增对象IndexRequest
* 3.客户端发送请求,获取响应对象
* 4.打印响应结果
*/
@Test
public void createDoc() throws IOException {
//1.创建请求对象:批量操作
BulkRequest request = new BulkRequest();
//2.批量操作中设置多个新增对象IndexRequest
IndexRequest addRequestOne = new
IndexRequest().id("1").type("_doc").index("heima3").source(XContentType.JSON,"id
",1L,"title","大米手机","category","手机","brand","小
米","price","2699.00","images","http://baidu.com");
request.add(addRequestOne);
IndexRequest addRequestTwo = new
IndexRequest().id("2").type("_doc").index("heima3").source(XContentType.JSON,"id
",2L,"title","大米手机","category","手机","brand","小
米","price","2699.00","images","http://baidu.com");
request.add(addRequestTwo);
//3.客户端发送请求,获取响应对象
BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
//4.打印响应结果
System.out.println("took::"+response.getTook());
System.out.println("Items::"+response.getItems());
} /
**
* 目标:批量删除
* 1.创建请求对象:批量删除
* 2.批量操作中设置多个删除对象DeleteRequest
* 3.客户端发送请求,获取响应对象
* 4.打印响应结果
*/
@Test
public void bulkDelete() throws IOException {
//1.创建请求对象:批量删除
BulkRequest request = new BulkRequest();
//2.批量操作中设置多个删除对象DeleteRequest
request.add(new DeleteRequest().id("1").type("_doc").index("heima3"));
request.add(new DeleteRequest().id("2").type("_doc").index("heima3"));
//3.客户端发送请求,获取响应对象
BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
//4.打印响应结果
System.out.println("took::"+response.getTook());
System.out.println("Items::"+response.getItems());
}
}
- 理解Elasticsearch的作用
- 分布式全文检索引擎,全文检索引擎的核心倒排索引技术,先创建索引在进行搜索的一个过
- 程
- 理解分词器的作用:将查询的条件拆分成关键词,用关键词去索引表中匹配查询文档
- 能够安装Elasticsearch服务
- 能够使用Elasticsearch集成IK分词器
- 理解Elasticsearch的相关概念:索引库的概念,类型的概念(7.0之后消失了)、文档、字段、映射
- 能够使用Kibana操作Elasticsearch == mysql数据库
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是rubygems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和rubygems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko
我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/
我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是
给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a
我有一个表,'jobs'和一个枚举字段'status'。status具有以下枚举集:enumstatus:[:draft,:active,:archived]使用ransack,我如何过滤表,比如说,所有事件记录? 最佳答案 你可以像这样在模型中声明自己的掠夺者:ransacker:status,formatter:proc{|v|statuses[v]}do|parent|parent.table[:status]end然后您可以使用默认的搜索语法_eq来检查相等性,如下所示:Model.ransack(status_eq:'ac