golang操作elasticsearch(oliver/elastic使用文档)
文章目录
- 1. 版本
- 2. 连接es
- 3. 索引操作
- 3.1 创建索引
- 3.2 判断索引是否存在
- 3.3 更新索引
- 3.4 删除索引
- 3.5 数据迁移
- 3.6 设置别名
- 4. 数据操作
- 4.1 新增或覆盖数据(单条)
- 4.2 根据id新增或更新数据(单条)
- 4.3 根据id新增或更新数据(批量)
- 4.4 根据条件更新数据
- 4.5 查询
- 5. 查询条件query设置
- 5.1 一个示例
- 5.2 match 模糊匹配
- 5.3 terms 精确匹配
- 5.4 range 范围匹配
- 5.5 nested 嵌套结构查询
- 5.6 更多
- 6. script painless语法
- 6.1 变量
- 6.2 if else
- 6.3 for循环
- 6.4 类型转换
- 7. script 实际应用
- 7.1 更新
- 7.2 自定义排序
1. 版本
示例运行环境:
go版本: 1.14
es版本: 6.7.0
工具及版本: github.com/olivere/elastic v6.2.35
此文章适合有go基础的人阅读, 因为代码示例中都是部分代码片段而不是完整可执行代码, 需要自行完善
2. 连接es
options := []elastic.ClientOptionFunc{elastic.SetURL("http://xxxxxxx:9200"),elastic.SetSniff(true), //是否开启集群嗅探elastic.SetHealthcheckInterval(10 * time.Second), //设置两次运行状况检查之间的间隔, 默认60selastic.SetGzip(false), //启用或禁用gzip压缩elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)), //ERROR日志输出配置elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)), //INFO级别日志输出配置
}
options = append(options, elastic.SetBasicAuth("xxxx", //账号"xxxxxxxxxxxxxx", //密码
))
con, err := elastic.NewClient(options...)
下述代码中 conf.ES() 表示con
3. 索引操作
3.1 创建索引
type mi = map[string]interface{}
mapping := mi{"settings": mi{"number_of_shards": 3,"number_of_replicas": 2,},"mappings": mi{"_doc": mi{ //type名"properties": mi{"id": mi{ //整形字段, 允许精确匹配"type": "integer",},"name": mi{"type": "text", //字符串类型且进行分词, 允许模糊匹配"analyzer": "ik_smart", //设置分词工具"search_analyzer": "ik_smart","fields": mi{ //当需要对模糊匹配的字符串也允许进行精确匹配时假如此配置"keyword": mi{"type": "keyword","ignore_above": 256,},},},"date_field": mi{ //时间类型, 允许精确匹配"type": "date",},"keyword_field": mi{ //字符串类型, 允许精确匹配"type": "keyword",},"nested_field": mi{ //嵌套类型"type": "nested","properties": mi{"id": mi{"type": "integer",},"start_time": mi{ //长整型, 允许精确匹配"type": "long",},"end_time": mi{"type": "long",},},},},},},
}
indexName := "xxxxxxxxxxxxxxxxxxxxx" //要创建的索引名
_, err = conf.ES().CreateIndex(indexName).BodyJson(mapping).Do(context.Background())
3.2 判断索引是否存在
//exists true 表示索引已存在
exists, err := conf.ES().IndexExists(indexName).Do(context.Background())
3.3 更新索引
仅支持添加字段, 已有字段无法修改
type mi = map[string]interface{}
mapping := mi{ "properties": mi{"id": mi{ //整形字段, 允许精确匹配"type": "integer",},},
}
_, err = conf.ES().PutMapping().Index(indexName).Type("_doc").BodyJson(mapping).Do(context.Background())
3.4 删除索引
_, err = conf.ES().DeleteIndex(indexName).Do(context.Background())
3.5 数据迁移
将一个索引的数据迁移到另一个索引中, 一般用于索引结构发生改变时使用新索引存储数据
type mi = map[string]interface{}
_, err = conf.ES().Reindex().Body(mi{"source": mi{"index": oldIndexName,},"dest": mi{"index": newIndexName,},
}).Do(context.Background())
3.6 设置别名
设置别名后就可以使用别名查询数据
_, err = conf.ES().Alias().Action(elastic.NewAliasAddAction(oldIndexName).Index(newIndexName),
).Do(context.Background())
4. 数据操作
4.1 新增或覆盖数据(单条)
此操作相同id的数据会被覆盖
_, err = conf.ES().Index().Index(indexName).Type("_doc").// id为字符串, 创建一条此id的数据或覆盖已有此id的记录// data为结构体或map, 当然结构需要跟索引的mapping类型保持一致Id(id).BodyJson(data).Do(context.Background())
4.2 根据id新增或更新数据(单条)
仅更新传入的字段, 而不是像 4.1 进行整条记录覆盖
_, err = conf.ES().Update().Index(t.index()).Type("_doc").Id(id).// data为结构体或map, 需注意的是如果使用结构体零值也会去更新原记录Upsert(data).// true 无则插入, 有则更新, 设置为false时记录不存在将报错DocAsUpsert(true). Do(context.Background())
4.3 根据id新增或更新数据(批量)
bulkRequest := conf.ES().Bulk()
// data map[int]interface{}, key为id, value为要更新的数据
for id, v := range data {doc := elastic.NewBulkUpdateRequest().Index(t.index()).Type("_doc").Id(strconv.Itoa(id)).Doc(v).// true 无则插入, 有则更新, 设置为false时记录不存在将报错DocAsUpsert(true)bulkRequest.Add(doc)
}
bulkResponse, err := bulkRequest.Do(context.Background())
if err != nil {return
}
// 获取操作失败的记录
bad := bulkResponse.Failed()
if len(bad) > 0 {s, _ := jsoniter.MarshalToString(bad)err = errors.New("部分记录更新失败 " + s)
}
4.4 根据条件更新数据
_, err = conf.ES().UpdateByQuery().Index(indexName).Type("_doc").//查询条件, 详细配置查询条件请查看章节 5Query(query).//要执行的更新操作, 详细配置请查看章节 6及7.1Script(script).Do(context.Background())
4.5 查询
_, err = conf.ES().Search().Index(indexName).//偏移量From(0).//返回数据的条数Size(10).//指定返回数据的字段(此处指定返回id和name), 全部返回则无需设置FetchSourceContext(elastic.NewFetchSourceContext(true).Include("id", "name")).//查询条件, 详细配置查询条件请查看章节 5Query(query).//按照id升序排序, 无需排序则可跳过此设置, 多个Sort会按先后顺序依次生效Sort("id", true).//自定义排序规则, 详细写法请查看章节 6及7.2SortBy(sorter).Do(context.Background())
5. 查询条件query设置
5.1 一个示例
{"bool": {"filter": [{"nested": {"path": "nested_field","query": {"range": {"nested_field.start_time": {"from": 1581475200,"include_lower": true,"include_upper": true,"to": null}}}}},{"nested": {"path": "nested_field","query": {"range": {"nested_field.end_time": {"from": null,"include_lower": true,"include_upper": true,"to": 1581481440}}}}}],"must": {"terms": {"id": [4181,4175]}}}
}
实现上述查询条件的go代码如下
query := elastic.NewBoolQuery()
query.Must(elastic.NewTermsQuery("id", []int{4181, 4175}))
query.Filter(elastic.NewNestedQuery("nested_field",// nested_field.start_time >= 1581475200elastic.NewRangeQuery("nested_field.start_time").Gte(1581475200),
))
query.Filter(elastic.NewNestedQuery("nested_field",// nested_field.start_time <= 1581481440elastic.NewRangeQuery("nested_field.end_time").Lte(1581481440),
))
5.2 match 模糊匹配
// name字段模糊匹配
elastic.NewMatchQuery("name", val)
5.3 terms 精确匹配
// name字段精确匹配
elastic.NewTermsQuery("name.keyword", val...)
5.4 range 范围匹配
// id >= 10, id <= 100
elastic.NewRangeQuery("id").Gte(10).Lte(100)
5.5 nested 嵌套结构查询
elastic.NewNestedQuery("nested_field",query, //此处query中的字段 都需要加上nested_field前缀, 比如 nested_field.id
)
5.6 更多
es query中的每一种查询结构都会有一个对应的go结构体, 此处不再过多赘述
6. script painless语法
官方文档
6.1 变量
int index = 1;
6.2 if else
if (index == -1) {// 逻辑
} else {//
}
6.3 for循环
for (om_cms_id in params.om_cms_ids) {continue
}
6.4 类型转换
// 数字转字符串
String.valueOf(11)
7. script 实际应用
7.1 更新
数据库中goods_id与omcms的关联关系存储如下
om_cms_id | goods_id |
---|---|
1 | 1, 2 |
2 | 1, 2 |
3 | 1 |
4 | 4 |
es中goods_id与omcms关联关系存储如下
goods_id | om_cms_id |
---|---|
1 | [1, 2, 3] |
2 | [1, 2, 4] |
当数据库中关联关系发生变换时要对应更新es中数据
- 获取omcms发生变化的记录
- 删除这些omcms在es中与goods的关联关系
- 添加omcms与goods的新关联关系
var goodsOmCmsIds = make(map[int][]int)
var goodsIds []interface{}
var omCmsIds []interface{}
for _, v := range list {omCmsIds = append(omCmsIds, v.Id)reg := regexp.MustCompile("^\\d+(,\\d+)*$")v.Ids = strings.ReplaceAll(v.Ids, "NaN", "0")if !reg.MatchString(v.Ids) {fmt.Println("不支持的格式:", v.Ids)continue}err = jsoniter.UnmarshalFromString("["+v.Ids+"]", &v.GoodsIds)if err != nil {return}for _, goodsId := range v.GoodsIds {if goodsId == 0 {continue}if _, ok := goodsOmCmsIds[goodsId]; !ok {goodsIds = append(goodsIds, goodsId)}goodsOmCmsIds[goodsId] = append(goodsOmCmsIds[goodsId], v.Id)}
}
// 查询出omcsm变更导致可能发生变更的所有商品
query := NewBoolQuery().Should(NewBoolQuery().Must(elastic.NewTermsQuery("id", goodsIds...)),NewBoolQuery().Must(elastic.NewTermsQuery("om_cms_id", omCmsIds...)),
)
script := elastic.NewScript(`for (om_cms_id in params.om_cms_ids) {if (ctx._source.om_cms_id == null) {continue}int index = ctx._source.om_cms_id.indexOf(om_cms_id);if (index == -1) {continue}ctx._source.om_cms_id.remove(index);}if (params.goods_om_cms_ids == null || params.goods_om_cms_ids[ctx._id] == null) {return}for (om_cms_id in params.goods_om_cms_ids[ctx._id]) {if (ctx._source.om_cms_id == null) {ctx._source.om_cms_id = [om_cms_id]} else {ctx._source.om_cms_id.add(om_cms_id)}}
`).Params(map[string]interface{}{"goods_om_cms_ids": goodsOmCmsIds,"goods_ids": goodsIds,"om_cms_ids": omCmsIds,
})
// 使用4.4更行方法
7.2 自定义排序
根据传入的id顺序排序
m := make(map[string]interface{})
// 循环要查询的id, 并转成map, key是id值, value是在原数组种的索引
for index, goodsId := range ids {m[strconv.Itoa(goodsId)] = index
}
sort := elastic.NewScriptSort(// params 存储自定义数据// doc 表示当前记录elastic.NewScript(`params.id[String.valueOf(doc['id'].value)]`).Param("id", m),"number",
).Order(vv[0] == 1)
golang操作elasticsearch(oliver/elastic使用文档)相关推荐
- 【Elasticsearch】java 操作 Elasticsearch 7.8 索引 文档 等操作
本文为博主九师兄(QQ:541711153 欢迎来探讨技术)原创文章,未经允许博主不允许转载.有问题可以先私聊我,本人每天都在线,会帮助需要的人. 文章目录 1.概述 2. 案例 2.1 引入依赖 2 ...
- golang操作elasticsearch详解
golang操作elasticsearch详解 直接上代码 package mainimport ("bytes""context""fmt" ...
- ElasticSearch修改和删除文档
ElasticSearch修改和删除文档 修改文档方式一:使用prepareUpdate,prepareIndex两者选其一皆可 client.prepareUpdate("blog2&qu ...
- 详细描述一下 Elasticsearch 更新和删除文档的过程。
1.删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更. 2.磁盘上的每个段都有一个相应的.del 文件.当删除请求发送后,文档并没有真的 ...
- GoLang官网怎么查看“包“文档
文章目录 一.GoLang官网怎么查看"包"文档 1.打开网址 2.点击入口 3.设置语言 4.设置中文 5.设置成功 二.查看GoLang中包(函数)的使用 1.进入网址首页 2 ...
- 如何操作 Office Open XML 格式文档
摘要: Office Open XML格式文件代替了早期的二进制Office系统文件.本文档向您介绍了包含在一个格式化文档中的组件以及展示这些文件功能的一些场景 . Frank Rice,微软公司 适 ...
- 如何操作 Office Open XML 格式文档(转)
原文地址为: 如何操作 Office Open XML 格式文档(转) 摘要: Office Open XML格式文件代替了早期的二进制Office系统文件.本文档向您介绍了包含在一个格式化文档中的组 ...
- 【MOS】OCR/Vote disk 维护操作: (添加/删除/替换/移动) (文档 ID 1674859.1)
[MOS]OCR/Vote disk 维护操作: (添加/删除/替换/移动) (文档 ID 1674859.1) 文档内容 目标 解决方案 准备磁盘 1. 磁盘大小 2. 裸设备或者块设备 ...
- Golang采用OpenXML标准写Word文档
Golang采用OpenXML标准写Word文档 Git路径:https://github.com/ErmaiSoft/GoOpenXml ##参考代码 package main import ( & ...
- elasticsearch 第五篇(文档操作接口)
INDEX API 示例: 1 2 3 4 5 PUT /test/user/1 { "name": "silence", "age": 2 ...
最新文章
- Java泛型三:通配符详解extends super
- 二进制bit0是什么意思_模拟信号是什么 模拟信号数字传输原理介绍【图文】
- RBM/DBN训练中的explaining away概念
- cuba.platform_CUBA Platform 6.3的新增功能
- 帆软决策报表嵌入html,在决策报表中使用网页框控件
- Android SDK Manager 在win8.1上的闪退问题【转载】
- 一加10 Pro的性能配置还是非常不错的
- UTF-8的CSV文件中文乱码问题解决办法
- 「PDF Expert」macOS 全能型 PDF 工具——功能介绍
- Django django.db.utils.ProgrammingError: (1146, Table 'django.member' doesn't exist)
- 常见网络设备口令备忘录
- 出售计算机广告英文作文,英语四级作文参考范文:二手电脑广告
- ensp配置服务器发布(将DMZ区的web服务区发布,供client访问)
- nodejs mysql process_nodeJS之进程process对象
- 超详细!!vue、vue-cli脚手架项目使用prerender-spa-plugin,解决SEO并为其添加title,keyWords,descript
- 从零开始实现mini-min网易云音乐(一)
- 清晰明了有趣味的数字加密讲解
- 漫画:滑动窗口入门题目,没有之一
- 【评测】Tecan品牌系列产品
- uniapp 顶部绝对定位
热门文章
- C#下对PDF文件进行电子图片签名
- PowerDesigner16配置显示注释comment配置方法
- 开源WPF第三方库【Newbeecoder.UI】分页控件
- 戴尔服务器加无线网卡用不了,戴尔笔记本无线网卡驱动如何安装?(已解决)...
- python打开xlsm_关于python:如何使用openpyxl使用Macro保存XLSM文件
- jquery广告浮动插件
- 【李小丫的笔记】DataWhale金融风控预测Task1
- np.max()、np.argmax()、np.maximum()、np.min()、np.argmin()、np.minimum()、np.sum()
- Google I/O 大会强势回归!2021 中文直播全攻略看这里
- 20大风控文本分类算法-基于字符级的tfidf+逻辑回归