目录
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数据库
kafka总结一.定义二.基础架构及术语三.工作流程分析3.1发送数据3.2保存数据3.2.1partition结构3.2.2message结构3.2.3存储策略3.2.4消费数据一.定义Kafka是一种高吞吐量的分布式发布订阅消息系统,可以处理消费者规模的网站中的所有动作流数据,具有高性能,持久化,多副本备份,横向扩展能力等。二.基础架构及术语Producer:生产者,消息的生产者,消息的入口Kafkacluster:Broker:brocker是kaf
1.操作Elasticsearch项目csmall-finish项目中node文件夹下共享了ES文档,命令都在里面,可以测试所有的代码都在"ES文档"中, 笔记略下面我们要学习使用java代码来操作ES2.SpringBoot操作Elasticsearch2.1SpringData简介原生状态下,我们使用JDBC连接数据库,因为代码过于繁琐,所以改为使用Mybatis框架在ES的原生状态下,我们java代码需要使用socket访问ES,但是也是过于繁琐,我们可以使用SpringData框架简化SpringData是Spring提供的一套连接各种第三方数据源的框架集我们需要使用的
文章目录一、ES的Docker部署二、Kibana:ES可视化部署三、服务端skywalking-oap部署四、可视化skywalking-ui部署五、Java应用引入agent5.1agent下载与配置5.2jar包启动带agent命令5.3在skywalking-ui查看监测内容一、ES的Docker部署#下载es镜像dockerpullelasticsearch:6.8.12#启动es镜像dockerrun--restart=always-p9200:9200-p9300:9300-e"discovery.type=single-node"-eES_JAV
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭7年前。社区在5个月前审查了是否重新打开这个问题,然后将其关闭:原始关闭原因未解决Improvethisquestion我维护着一个用Delphi7编写的旧的仅限PC的应用程序。尽管Delphi在过去为我提供了很好的服务,但我现在只将它用于这个应用程序,并且发现我的语言技能正在下降。它的语法与我的“日常工作”语言Java/Ruby差别太大,所以我需要更长的时间才能开始编写新代码,而且它太旧了,我没有使用过很多接口
进入你的iis机器级别设置并添加<deploymentretail="true"/>如http://msdn.microsoft.com/en-us/library/ms228298.aspx中所述创建一个新的web项目,添加一个标签,然后添加以下代码。protectedvoidPage_Load(objectsender,EventArgse){Label1.Text=HttpContext.Current.IsDebuggingEnabled.ToString();}//Result:true我错过了什么?更新:我更新了机器配置的64位和32位版本的值。
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭7年前。Improvethisquestion由于我的下一个项目(很多SOA的东西),我需要一个基于组件的配置并存储在数据库中以启用中央管理。app.config/web.config不支持任何这些要求(不过我知道一些与应用程序域有关的黑客攻击)。那么你们中有人知道配置框架吗?它不一定是免费的。我知道如何使用google;-),但如果您有一些关于您已使用的框架的经验,我将不胜感激。提前致谢!弗洛
在设计大型应用程序时,我正在努力了解思考过程。假设我有一个客户需要一个新的客户网站,他估计每天有40,000个订单,而用户群已经有25,000个。在设计应用程序时,您如何确定是否需要分布式架构?我应该使用网络农场吗?等我过去主要构建2层(物理)应用程序,我真的想提高我的理解。任何见解都会很棒! 最佳答案 从一开始就对您的新应用进行负载测试。由于预先进行大型设计永远不会给您带来预期的结果(15年以上的经验),所以最好的办法是针对变化进行设计,让正确的架构从您的需求中浮现出来。根据您的描述,对该项目采用敏捷方法,并使用其实践来指导您的项
.NET框架中线程的状态在thislink中有解释。.我最近在一个网站上看到了这张照片,我想到了几个问题:操作系统中的线程生命周期与.NET框架中的线程生命周期并不完全一致。有人可以提供与操作系统中的状态与.NET框架相匹配的资源吗?我们在.NET框架中没有称为Blocked的状态。如果线程发出I/O请求,它会处于什么状态?Aborted状态的目的是什么?当线程调用Abort()方法时,会进入AbortRequested状态,线程响应中止请求后,会进入Stopped状态强>状态。那么Aborted状态的作用是什么呢? 最佳答案 如果
我正在使用NEST库与ElasticSearch交互,并且我正在尝试找出一种基于非类型数据构建索引类型/嵌套对象的方法。该类型具有以下基本结构。publicclassEntity:DynamicObject{publicstringId{get;set;}//abunchofothersimplepropertiespublicoverrideIEnumerable<string>GetDynamicMemberNames(){returnData.Select(x=>x.Name);}publicoverrideboolTryGetMember(GetMemberB
我一直在学习IoC、依赖注入(inject)等,并且很享受这个过程。对我来说,接口(interface)解耦和编程的好处是显而易见的。但是,我真的不喜欢将自己绑定(bind)到Unity或Autofac或Windsor等特定框架-因为我仍在学习并且尚未决定哪个最适合我的目的。那么,我如何围绕Unity之类的东西进行包装,以便以后可以轻松地切换到Windsor?(管他呢)。而且你敢说用另一个注入(inject)第一个;)谢谢!R.附言我将Unity标记为我目前的个人偏好(我只是喜欢Entlib)。 最佳答案 您当然可以通过使用Reso
我想关闭当前使用的表单(MainForm),然后打开第二个表单(Form)。我试过:privatevoidbuttonStartQuiz_Click(objectsender,EventArgse){this.Close();Form2form2=newForm2();form2.ShowDialog();}或者在form2.ShowDialog()之后添加this.Close();也不起作用。有什么提示吗?编辑:还可以通过在form2.ShowDialog()之后添加this.Close()添加它,它仅在我关闭新表单时关闭。如果我改为选择form2.Show(),它会立即关闭这两个表
publicclassA{intx;floaty;}如何在C#中查找类的大小。有没有像Sizeof()这样的运算符,以前是C++的 最佳答案 以下将为您提供C#类的大小:Marshal.SizeOf(typeof(Myclass));usingSystem.Runtime.InteropServices;[StructLayout(LayoutKind.Sequential)]classMyclass{}记住类的大小取决于填充。 关于c#-如何在C#中查找类的大小,我们在StackOve
我有一个WCF服务引用:http://.../Service.svc(?WSDL)我有一个包含兼容SOAP信封的XML文件<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><MyXML>...现在,我想通过一些C#代码将此原始数据直接发送到服务(并接收响应),而不使用VisualStudio服务引用。这是否可能,如果可能,如何实现? 最佳答案 你可以使用U
我对.NET比较陌生,并且使用Linq2Sql已经快一年了,但它缺少我现在正在寻找的一些功能。我将开始一个新项目,我想在其中使用具有以下特征的ORM:它必须非常高效,我不想处理访问层来从数据库中保存或检索对象,但它应该允许我在实际将其提交到数据库之前轻松调整任何对象;它还应该允许我轻松地使用不断变化的数据库模式它应该允许我扩展从数据库映射的对象,例如向它们添加虚拟属性(虚拟列到表)它必须(至少几乎)与数据库无关,它应该允许我以透明的方式使用不同的数据库它必须没有那么多配置或必须基于约定才能使其工作它应该允许我使用Linq那么,你知道我可以使用的任何ORM吗?感谢您的帮助。编辑我知道一个
我目前有一个功能:publicstaticAttributeGetAttribute(MemberInfoMember,TypeAttributeType){Object[]Attributes=Member.GetCustomAttributes(AttributeType,true);if(Attributes.Length>0)return(Attribute)Attributes[0];elsereturnnull;}我想知道是否值得将一个属性的所有属性缓存到一个Attribute=_cache[MemberInfo][Type]字典,这需要使用不带任何类型参数的GetC
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我已经有10年的编程经验,主要是使用vba和vb.net,但我对C#的了解足以编写我通常做的程序。我昨天申请了高级c#职位,但我在入职测试中表现很差,这可不好笑:)我一直发现,对我来说,学习和记忆的最佳方式是通过问答(多项选择题和简答题)。也就是说,提出一个问题,在我回答后立即反馈我的选择是对还是错以及原因。因此,我想知道是否有人知道或可以推荐一个C#测
这个问题在这里已经有了答案:关闭13年前。PossibleDuplicate:HowtosortanarrayofobjectbyaspecificfieldinC#?给定以下代码:MyClassmyClass;MyClassArray[]myClassArray=newMyClassArray[10];for(inti;i<10;i++;){myClassArray[i]=newmyClass();myClassArray[i].Name=GenerateRandomName();}最终结果可能如下所示:myClassArray[0].Name//'John';
只是想知道是否有人知道以下问题的优雅解决方案。如果我有2009年6月30日并且我添加一个月,我希望它转到2009年7月31日,而不是2009年7月30日。此逻辑基于以下事实:2009年6月30日是6月的月底,当我添加一个月时,我想转到下个月的月底。但是如果我有2009年6月29日并且我添加一个月它应该去2009年7月29日。请注意,我需要能够添加任意数量的月份,并且我需要考虑闰年。我也知道这里的逻辑是有问题的,但这是一项业务需求,适用于月末契约(Contract)将在未来一个月结束。我想过几个解决方案,但没有一个是非常优雅的。因此我在想有人可能有更好的方法。干杯安东尼
我是C#新手,没有任何编程经验。但我已经完成了C#基础知识。现在我想通过添加父节点和子节点来设计一个简单的TreeView。我想为第二个节点添加第二个子节点,我被困在这里,不知道下一步是什么。有什么想法吗?代码如下:privatevoidaddParentNode_Click(objectsender,EventArgse){stringyourParentNode;yourParentNode=textBox1.Text.Trim();treeView2.Nodes.Add(yourParentNode);}privatevoidaddChildNode_Click(objectse
重复Ondesignpatterns:WhenshouldIusethesingleton?classSingleton{privatestaticSingletoninstance;privateSingleton(){}publicstaticSingletonInstance{get{if(instance==null)instance=newSingleton();returninstance;}}} 最佳答案 简单。单例做什么?它提供对对象实例的全局访问,并且它保证永远不会创建超过一个该类型的实例。因此,当您需要两者这些东