ES+java操作ES

1.ES文档操作

1.1 什么是ES中的文档

document --存放数据
在ES里面 通过index索引库 type 类型(表) 行({id:name:}) 列 id /name
ES是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在ES中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。
ES使用Javascript对象符号(JavaScript Object Notation),也就是JSON,作为文档序列化格式。JSON现在已经被大多语言所支持,而且已经成为NoSQL领域的标准格式。

一个文档不只有数据。它还包含元数据(metadata)—关于文档的信息。三个必须的元数据节点是:
在这里插入图片描述
_index:
索引库,类似于关系型数据库里的“数据库”—它是我们存储和索引关联数据的地方。

_type:
在应用中,我们使用对象表示一些“事物”,例如一个用户、一篇博客、一个评论,或者一封邮件。可以是大写或小写,不能包含下划线或逗号。我们将使用 employee 做为类型名。

_id:
与 _index 和 _type 组合时,就可以在ELasticsearch中唯一标识一个文档。当创建一个文档,你可以自定义 _id ,也可以让Elasticsearch帮你自动生成。

另外还包括:_uid 文档唯一标识(_type#_id)
_source: 文档原始数据
_all: 所有字段的连接字符串

1.2 文档的增删改

在ES中存储数据的行为就叫做索引(indexing),文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以简单的对比传统数据库和ES的对应关系:
关系数据库(MYSQL) -> 数据库DB-> 表TABLE-> 行ROW-> 列Column
Elasticsearch -> 索引库Indices -> 类型Types -> 文档Documents -> 字段Fields
ES集群可以包含多个索引(indices)(数据库),每一个索引库中可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。

1.3 创建索引文档

①使用自己的ID创建:

PUT {index}/{type}/{id}
{
  "field": "value",
  ...
}

②ES内置ID创建:

POST {index}/{type}/
{
 "field": "value",
 ...
}

①②ES响应内容:

{
"_index": "itsource",
"_type": "employee",
"_id": xxxxxx,
"_version": 1, //文档版本号
"created": true //是否新增
}

③ 获取指定ID的文档
GET crud/employee/123?pretty
** ④ 返回的内容:**

{
"_index" : "crud",
"_type" : "employee",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
   "email": "xxx@qq.com",
   "fullName": "xxxx",
   ...
}
}

返回文档的部分字段:
GET默认返回整个文档,通过GET /crud/employee/123?_source=fullName,email
只返回文档内容,不要元数据:
GET crud/employee/123/_source
④ 修改文档
更新整个文档
post {index}/{type}/{id}

Id:1,
Name:xx

在响应中,我们可以看到Elasticsearch把 _version 增加了。
{

“_version” : 2,
“created”: false
}
created 标识为 false 因为同索引、同类型下已经存在同ID的文档。
在内部,Elasticsearch已经标记旧文档为删除并添加了一个完整的新文档。旧版本文档不会立即消失,但你也不能去访问它。Elasticsearch会在你继续索引更多数据时清理被删除的文档。
局部更新文档
接受一个局部文档参数 doc,它会合并到现有文档中,对象合并在一起,存在的标量字段被覆盖,新字段被添加。

POST itsource/employee/123/_update
{
“doc”:{
"email" : "nixianhua@itsource.cn", 
"salary": 1000
}
}

email会被更新覆盖,salary会新增。
这个API 似乎 允许你修改文档的局部,但事实上Elasticsearch
遵循与之前所说完全相同的过程,这个过程如下:

  1. 从旧文档中检索JSON
  2. 修改它
  3. 删除旧文档
  4. 索引新文档

脚本更新文档
也可以通过使用简单的脚本来进行。这个例子使用一个脚本将age加5:
POST crud/emploee/123/_update
{
“script” : “ctx._source.age += 5”
}
在上面的例子中, ctx._source指向当前被更新的文档。
注意,目前的更新操作只能一次应用在一个文档上。

删除文档
DELETE {index}/{type}/{id}
存在文档的返回:
{
“found” : true,
“_index” : “website”,
“_type” : “blog”,
“_id” : “123”,
“_version” : 3
}
不存在的返回:
{
“found” : false,
“_index” : “website”,
“_type” : “blog”,
“_id” : “123”,
“_version” : 4
}
注意:尽管文档不存在,但_version依旧增加了。这是内部记录的一部分,它确保在多节点间不同操作可以有正确的顺序。
批量操作bulk API – 后台java程序api
使用单一请求来实现多个文档的create、index、update 或 delete。
Bulk请求体格式:
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
每行必须以 “\n” 符号结尾,包括最后一行。这些都是作为每行有效的分离而做的标记。
create当文档不存在时创建之。
index创建新文档或替换已有文档。
update局部更新文档。
delete删除一个文档。
例如:
POST _bulk
{ “delete”: { “_index”: “crud”, “_type”: “employee”, “_id”: “123” }}
{ “create”: { “_index”: “crud”, “_type”: “blog”, “_id”: “123” }}
{ “title”: “我发布的博客” }
{ “index”: { “_index”: “crud”, “_type”: “blog” }}
{ “title”: “我的第二博客” }
注意:delete后不需要请求体,最后一行要有回车

1.4 文档的简单查询
1.4.1 通过文档ID获取

GET crud/employee/1

1.4.2 批量获取

mget API参数是一个 docs数组,数组的每个节点定义一个文档的 _index 、 _type 、 _id 元数据。如果你只想检索一个或几个确定的字段,也可以定义一个 _source 参数:
方式1:GET _mget
{
“docs” : [
{
“_index” : “itsource”,
“_type” : “blog”,
“_id” : 2
},
{
“_index” : “itsource”,
“_type” : “employee”,
“_id” : 1,
“_source”: “email,age”
}
]
}
方式2:同一个索引库的同一个类型下
GET itsource/blog/_mget
{
“ids” : [ “2”, “1” ]
}

1.4.3 空搜索

没有指定任何的查询条件,只返回集群索引中的所有文档:
GET _search

1.4.4 分页搜索

和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:
size : 每页条数,默认 10 pageSize
from : 跳过开始的结果数,默认 0 beginIndex limit beginIndex,pageSie
如果你想每页显示5个结果,页码从1到3,那请求如下:
GET _search?size=5
GET _search?size=5&from=5
GET _search?size=5&from=10

1.4.5查询字符串搜索

一个搜索可以用纯粹的uri来执行查询。在这种模式下使用搜索,并不是所有的选项都是暴露的。它可以方便快速进行 curl 测试。
查询年龄为25岁的员工
GET itsource/employee/_search?q=age:25
age[20 TO 30]

2.DSL查询与过滤

2.1 DSL查询

由ES提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。
DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。我们可以这样表示之前关于“老郑”的查询:
查询字符串模式(查询条件很少):GET crud/employee/_search?q=fullName:xx
DSL模式(查询条件很多):
GET crud/employee/_search
{
“query” : {
“match” : {
“fullName” : “xxx”
}
}
}

模拟匹配
GET crud/employee/_search
{
“query”: {
“wildcard” : { “name” : “cc” }
}
}

对于简单查询,使用查询字符串比较好,但是对于复杂查询,由于条件多,逻辑嵌套复杂,查询字符串不易组织与表达,且容易出错,因此推荐复杂查询通过DSL使用JSON内容格式的请求体代替。

2.2 DSL查询和DSL过滤
DSL查询

使用DSL查询,必须要传递query参数给ES。
GET _search
{“query”: YOUR_QUERY_HERE}

一个常用的相对完整的DSL查询:
GET crud/employee/_search
{
“query”: {
“match_all”: {}
},
“from”: 20,
“size”: 10,
“_source”: [“fullName”, “age”, “email”],
“sort”: [{“join_date”: “desc”},{“age”: “asc”}]
}

上面查询 表示 查询所有数据,查询fullName,age和email,按照加入日期和年龄进行排序

DSL过滤

DSL过滤语句和DSL查询语句非常相似,但是它们的使用目的却不同 :
DSL过滤 查询文档的方式更像是对于我的条件“有”或者“没有”,–精确查询
而DSL查询语句则像是“有多像”。–类似于模糊查询

DSL过滤和DSL查询在性能上的区别 :
过滤结果可以缓存并应用到后续请求。
查询语句同时 匹配文档,计算相关性,所以更耗时,且不缓存。
过滤语句 可有效地配合查询语句完成文档过滤。

原则上,使用DSL查询 做模糊查询 或其他需要进行相关性评分的场景,其它全用DSL过滤。

用法

{
“query”: {
“bool”: { 与(must) 或(should) 非(must not)
“must”: [
{“match”: {“description”: “search” }}
],
“filter”: {
“term”: {“tags”: “lucene”}
}
}
},
“from”: 20,
“size”: 10,
“_source”: [“fullName”, “age”, “email”],
“sort”: [{“join_date”: “desc”},{“age”: “asc”}]
}

2.3 使用DSL查询与过滤
① 全匹配(match_all

普通搜索(匹配所有文档):
{
“query” : {
“match_all” : {}
}
}

如果需要使用过滤条件(在所有文档中过滤,红色部分默认可不写):
GET _search
{
“query”: {
“bool”: {
“must”: [
{
“match_all”: {}
}
],
“filter”: {
“term”: {
“name”: “zs1”
}
}
}
}
}

② 标准查询(match和multi_match)

match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用match查询一个全文本字段,它会在真正查询之前用分析器先分析查询字符:
{
“query”: {
“match”: {
“fullName”: “Steven King”
}
}
}

上面的搜索会对Steven King分词,并找到包含Steven或King的文档,然后给出排序分值。
如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed的字符串时,它将为你搜索你给定的值,如:
{ “match”: { “age”: 26 }}
{ “match”: { “public”: true }}
{ “match”: { “tag”: “full_text” }}

multi_match 查询允许你做 match查询的基础上同时搜索多个字段:
{
“query”:{
“multi_match”: {
“query”: “Steven King”,
“fields”: [ “fullName”, “title” ]
}
}
}
selec
t * from employee where fullName = ‘steven King’ or tile = ‘steven King’
上面的搜索同时在fullName和title字段中匹配。
提示:match一般只用于全文字段的匹配与查询,一般不用于过滤。

③单词搜索与过滤(Term和Terms)

{
“query”: {
“bool”: {
“must”: {
“match_all”: {}
},
“filter”: {
“term”: {
“tags”: “elasticsearch”
}
}
}
}
}
Terms搜索与过滤
{
“query”: {
“terms”: {
“tags”: [“jvm”, “hadoop”, “lucene”],
“minimum_match”: 2
}
}
}
minimum_match:至少匹配个数,默认为1

④ 组合条件搜索与过滤(Bool)

组合搜索bool可以组合多个查询条件为一个查询对象,查询条件包括must、should和must_not。
例如:查询爱好有美女,同时也有喜欢游戏或运动,且出生于1990-06-30及之后的人。
{
“query”: {
“bool”: {
“must”: [{“term”: {“hobby”: “美女”}}],
“should”: [{“term”: {“hobby”: “游戏”}},
{“term”: {“hobby”: “运动”}}
],
“must_not”: [
{“range” :{“birth_date”:{“lt”: “xxxxxxx”}}}
],

查询你的爱好 必须 美女 或者 你爱好 游戏或者运动 ,你必须是90后
"filter": […],
“minimum_should_match”: 1
}
}
}

Hobby=美女 and (hobby=游戏 or hobby=运动) and birth_date >= 1990-06-30
提示: 如果 bool 查询下没有must子句,那至少应该有一个should子句。但是 如果有 must子句,那么没有 should子句也可以进行查询。

⑤ 范围查询与过滤(range)

range过滤允许我们按照指定范围查找一批数据:
{
“query”:{
“range”: {
“age”: {
“gte”: 20,
“lt”: 30
}
}
}
}

上例中查询年龄大于等于20并且小于30。
gt:> gte:>= lt:< lte:<=

⑥ 存在和缺失过滤器(exists和missing)

{
“query”: {
“bool”: {
“must”: [{
“match_all”: {}
}],
“filter”: {
“exists”: { “field”: “gps” }
}
}
}
}

提示:exists和missing只能用于过滤结果。

⑦ 前匹配搜索与过滤(prefix)

和term查询相似,前匹配搜索不是精确匹配,而是类似于SQL中的like ‘key%’
{
“query”: {
“prefix”: {
“fullName”: “倪”
}
}
}

select * from xxx where fullName like ‘倪%’
上例即查询姓倪的所有人。

⑧ 通配符搜索(wildcard)

使用代表0~N个,使用?代表1个。
**{
“query”: {
“wildcard”: {
“fullName”: "倪
华"
}
}
}**
select * from xxx where fullName like ‘倪%华’

3. 分词与映射

3.1 分词与映射

在全文检索理论中,文档的查询是通过关键字查询文档索引来进行匹配,因此将文本拆分为有意义的单词,对于搜索结果的准确性至关重要,因此,在建立索引的过程中和分析搜索语句的过程中都需要对文本串分词。
ES中分词需要对具体字段指定分词器等细节,因此需要在文档的映射中明确指出。

3.2 IK分词器

ES默认对英文文本的分词器支持较好,但和lucene一样,如果需要对中文进行全文检索,那么需要使用中文分词器,同lucene一样,在使用中文全文检索前,需要集成IK分词器。
下载
ES的IK分词器插件源码地址:https://github.com/medcl/elasticsearch-analysis-ik

将IK放置于ES根目录/plugins/ik
分词器(可默认)
词典配置:config/IKAnalyzer.cfg.xml
重启ES
测试分词器
POST _analyze
{
“analyzer”:“ik_smart”,
“text”:“中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首”
}
注意:IK分词器有两种类型,分别是ik_smart分词器ik_max_word分词器。
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;

4. 文档映射Mapper

ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。

4.1 ES字段类型

① 基本字段类型

字符串:text(分词),keyword(不分词) StringField(不分词文本),TextFiled(要分词文本)
text默认为全文文本,keyword(关键字)默认为非全文文本
数字:long,integer,short,double,float
日期:date
逻辑:boolean
{user:{“key”:value}}
{hobbys:[xxx,xx]}

② 复杂数据类型

对象类型:object
数组类型:array
地理位置:geo_point,geo_shape

4.2 默认映射

查看索引类型的映射配置:GET {indexName}/_mapping/{typeName}
ES在没有配置Mapping的情况下新增文档,ES会尝试对字段类型进行猜测,并动态生成字段和类型的映射关系。
在这里插入图片描述

4.3 简单类型映射

字段映射的常用属性配置列表
在这里插入图片描述
"city": {
“type”: “text”,
“analyzer”: “ik_smart”,
“fields”: {
“raw”: {
“type”: “keyword”
}
}
}

有些类型 有时候需要分词 有时候不需要分词
city分词
city.raw 不分词
那么以后搜索过滤和排序就可以使用city.raw字段名

① 针对单个类型的映射配置方式

查询映射类型:
GET shop/goods/_mapping
修改映射类型
(1)Delete shop;
(2)PUT shop;
(3)POST shop/goods/_mapping
{
“goods”: {
“properties”: {
“price”: {
“type”: “integer”
},
“name”: {
“type”: “text”,
“analyzer”: “ik_smart”,
“search_analyzer”: “ik_smart”
}
}
}
}
(4)加入数据
put shop/goods/1
{
“price”:88,
“name”: “iphone8”
}

注意:你可以在第一次创建索引的时候指定映射的类型。此外,你也可以晚些时候为新类型添加映射(或者为已有的类型更新映射)。

你可以向已有映射中增加字段,但你不能修改它。如果一个字段在映射中已经存在,这可能意味着那个字段的数据已经被索引。如果你改变了字段映射,那已经被索引的数据将错误并且不能被正确的搜索到。
我们可以更新一个映射来增加一个新字段,但是不能把已有字段的类型那个从 analyzed 改到 not_analyzed。

② 同时对多个类型的映射配置方式

PUT {indexName}
{
“mappings”: {
“user”: {
“properties”: {
“id”: {
“type”: “integer”
},
“info”: {
“type”: “text”,
“analyzer”: “ik_smart”,
“search_analyzer”
}
}
},
“dept”: {
“properties”: {
“id”: {
“type”: “integer”
},
…更多字段映射配置
}
}
}
}

4.4 对象及数组类型映射–了解
① 对象的映射与索引

{
“id” : 1,
“girl” : {
“name” : “王小花”,
“age” : 22
}
}
对应的mapping配置:
{
“properties”: {
“id”: {“type”: “long”},
“girl”: {
“properties”:{
“name”: {“type”: “keyword”},
“age”: {“type”: “integer”}
}
}
}
}

② 数组与对象数组

注意:数组中元素的类型必须一致。
{
“id” : 1,
“hobby” : [“王小花”,“林志玲”]
}
对应的mapping配置是:
{
“properties”: {
“id”: {“type”: “long”},
“hobby”: {“type”: “keyword”}
}
}

对象数组的映射–用不上
{
“id” : 1,
“girl”:[{“name”:“dlrb”,“age”:32},{“name”:“赵丽颖”,“age”:22}]
}
对应的映射配置为:
“properties”: {
“id”: {
“type”: “long”
},
“girl”: {
“properties”: {
“age”: { “type”: “integer” },
“name”: { “type”: “text” }
}
}
}
-----------put
[{
Age:31
Name:林志玲
},{
Age:22
Name:赵丽颖
}]

注意:同内联对象一样,对象数组也会被扁平化索引
{
“user1.girl.age”: [32, 22],
“user2.girl.name”: [“林志玲”, “赵丽颖”]
}

4.5全局映射

全局映射可以通过动态模板和默认设置两种方式实现。
默认方式:default
索引下所有的类型映射配置会继承_default_的配置,如:
PUT {indexName}
{
“mappings”: {
default”: {
“_all”: {
“enabled”: false 关闭默认映射配置
}
},
“user”: {
//指定自己的自定义配置
},
“dept”: {
“_all”: {
“enabled”: true //启动默认配置
}

},

}
}

动态模板:dynamic_templates
注意:ES会默认把string类型的字段映射为text类型(默认使用标准分词器)和对应的keyword类型,如:
"name": {
“type”: “text”,
“fields”: {
“keyword”: {
“type”: “keyword”,
“ignore_above”: 256
}
}
}

在实际应用场景中,一个对象的属性中,需要全文检索的字段较少,大部分字符串不需要分词,因此,需要利用全局模板覆盖自带的默认模板:
PUT _template/global_template //创建名为global_template的模板
{
“template”: “", //匹配所有索引库
“settings”: { “number_of_shards”: 1 }, //匹配到的索引库只创建1个主分片
“mappings”: {
default”: {
“_all”: {
“enabled”: false //关闭所有类型的_all字段
},
“dynamic_templates”: [
{
“string_as_text”: {
“match_mapping_type”: “string”,//匹配类型string
“match”: "
_text”, //匹配字段名字以_text结尾
“mapping”: {
“type”: “text”,//将类型为string的字段映射为text类型
“analyzer”: “ik_max_word”,
“search_analyzer”: “ik_max_word”
}
}
},
{
“string_as_keyword”: { a
“match_mapping_type”: “string”,//匹配类型string
“mapping”: {
“type”: “keyword”//将类型为string的字段映射为keyword类型
}
}
}
]
}
}}

上面的意思:就是如果索引库里面字段 以_text结尾 就需要进行分词,如果不是,就不分词
测试:
(1)拷贝上面代码执行
(2)删除库 delete shop
(3)创建库 put shop
(4)加入数据测试

POST shop/goods/5
{
“id”:12,
“name_text”:”iphone x”,
“local“:”cnsssss”
}

说明:上例中定义了两种动态映射模板string_as_text和string_as_keyword.
在实际的类型字段映射时,会依次匹配:
①字段自定义配置
②全局配置
③默认配置

4.6 最佳实践

(1)有历史数据不做映射
(2)根据优先级来
步骤
(1)如果有库 先删除库 ,如果没有库 ,就创建库
(2)建库
(3)做全局映射 --动态模板
(4)做自定义映射
(5)操作crud

5 ES集群

5.1为什么需要集群

1)单点故障
2)高并发
3)海量数据

5.2 ES集群相关概念

ES 的1个集群中放多个节点,放多个shard(shard又分成主的shard和从shard)

ES cluster(1)—Node()-Shard()

ES节点类型Node有三种节点:
master Node:主节点,维护集群信息 索引库操作
data node:数据节点, 文档crud
client node:只负责处理用户请求

通过两个属性进行设置: node.master node.data

1、默认情况下,每个节点都有成为主节点的资格,也会存储数据,还会处理客户端的请求。- 在生产环境下,如果不修改ElasticSearch节点的角色信息,在高数据量,高并发的场景下集群容易出现脑裂等问题
2、在一个生产集群中我们可以对这些节点的职责进行划分。建议集群中设置3台以上的节点作为master节点【node.master: true node.data: false】,这些节点只负责成为主节点,维护整个集群的状态。
3、再根据数据量设置一批data节点【node.master: false node.data: true】,这些节点只负责存储数据,后期提供建立索引和查询索引的服务,这样的话如果用户请求比较频繁,这些节点的压力也会比较大。
4、在集群中建议再设置一批client节点【node.master: false node.data: false】,这些节点只负责处理用户请求,实现请求转发,负载均衡等功能。

5.3 集群理解

5.3.1 shard&replica机制再次梳理以及单node环境中创建index图解

①图解单node环境下创建index是什么样子的
1)单node环境下,创建一个index,有3个primary shard,3个replica shard
(2)集群status是yellow
(3)这个时候,只会将3个primary shard分配到仅有的一个node上去,另外3个replica shard是无法分配的
(4)集群可以正常工作,但是一旦出现节点宕机,数据全部丢失,而且集群不可用,无法承接任何请求
在这里插入图片描述

5.4 node环境下replica shard分配

(1)replica shard分配:3个primary shard,3个replica shard,2 node
(2)primary —> replica同步
(3)读请求:primary/replica
在这里插入图片描述

5.5 图解横向扩容过程,如何超出扩容极限,以及如何提升容错性

在这里插入图片描述
(1)primary&replica自动负载均衡,6个shard,3 primary,3 replica
(2)每个node有更少的shard,IO/CPU/Memory资源给每个shard分配更多,每个shard性能更好
(3)扩容的极限,6个shard(3 primary,3 replica),最多扩容到6台机器,每个shard可以占用单台服务器的所有资源,性能最好
(4)超出扩容极限,动态修改replica数量,9个shard(3primary,6 replica),扩容到9台机器,比3台机器时,拥有3倍的读吞吐量
(5)3台机器下,9个shard(3 primary,6 replica),资源更少,但是容错性更好,最多容纳2台机器宕机;

(6)这里的这些知识点,你综合起来看,就是说,一方面告诉你扩容的原理,怎么扩容,怎么提升系统整体吞吐量;另一方面要考虑到系统的容错性,怎么保证提高容错性,让尽可能多的服务器宕机,保证数据不丢失

5.6 图解ES容错机制:master选举,replica容错,数据恢复

在这里插入图片描述
(1)6 shard,3 node
(2)master node宕机,自动master选举,red
(3)replica容错:新master将replica提升为primary shard,yellow
(4)重启宕机node,master copy replica到该node,使用原有的shard并同步宕机后的修改,green

6.Java API(ES)

6.1 导包
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>5.2.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.7</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.7</version>
</dependency>
6.2 创建文档索引
 //连接es服务方法 嗅探方式 
    public TransportClient getClient() throws Exception{
        Settings settings = Settings.builder()
                .put("client.transport.sniff", true).build();
        TransportClient client = new PreBuiltTransportClient(settings)
                .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
        return client;
    }
6.2 获取文档
 @Test
    public void testGet() throws Exception{
        //得到client
        TransportClient client = getClient();
        System.out.println(client.prepareGet("aisell", "user", "1").get().getSource());
        client.close();
    }
6.3 新增文档
@Test
    public void testES() throws Exception{
        //得到client
        TransportClient client = getClient();
        IndexRequestBuilder builder = client.prepareIndex("aisell", "user", "1");
        Map mp = new HashMap();
        mp.put("name","xxxyy");
        mp.put("age",18);

        builder.setSource(mp);
        IndexResponse indexResponse = builder.get();
        System.out.println(indexResponse);
        client.close();

    }
6.3 修改文档
 @Test
    public void testUpdate() throws Exception{
        TransportClient client = getClient();
        IndexRequest indexRequest = new IndexRequest("aisell", "user", "1");
        Map mp = new HashMap();
        mp.put("name","test123");
        mp.put("age",28);
        //不存在 就新增 存在 就更新
        UpdateRequest updateRequest = new UpdateRequest("aisell", "user", "1").doc(mp).upsert(indexRequest);
        //执行
        client.update(updateRequest).get();
        client.close();

    }
6.4 删除文档
@Test
    public void testDel() throws Exception{
        TransportClient client = getClient();
        client.prepareDelete("aisell","user","1").get();
        client.close();
        
    }
6.5 批量操作文档
 @Test
    public void testBulk() throws Exception{
        TransportClient client = getClient();
        BulkRequestBuilder req = client.prepareBulk();
        for(int i=1;i<50;i++){
            Map mp = new HashMap();
            mp.put("name","tt"+i);
            mp.put("age",18+i);      req.add(client.prepareIndex("shoppings","goods",""+i).setSource(mp));
        }
        BulkResponse responses = req.get();
        if(responses.hasFailures()){
            System.out.println("插错了");
        }
    }
6.6 分页 排序 过滤
 @Test
    public void testDSL() throws Exception{
        //得到client对象
        TransportClient client = getClient();
        //得到builder
        SearchRequestBuilder builder = client.prepareSearch("shoppings").setTypes("goods");
        //得到bool对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //得到must
        List<QueryBuilder> must = boolQuery.must();
        must.add(QueryBuilders.matchAllQuery());
        //添加filter过滤器      boolQuery.filter(QueryBuilders.rangeQuery("age").gte("18").lte("58"));
        builder.setQuery(boolQuery);
        //添加分页
        builder.setFrom(0);
        builder.setSize(10);
        //设置排序
        builder.addSort("age", SortOrder.DESC);
        //设置查询字段
        builder.setFetchSource(new String[]{"name","age"},null);
        //取值
        SearchResponse response = builder.get();
        //得到查询内容
        SearchHits hits =  response.getHits();
        //得到命中数据 返回数组
        SearchHit[] hitsHits = hits.getHits();
        //循环数组 打印获取值
        for (SearchHit hitsHit : hitsHits) {
            System.out.println("得到结果"+hitsHit.getSource());
        }
    }
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值