elasticsearch-文档(三)
文档
elasticsearch是通过document的形式存储数据的,个人理解文档就是一条数据一个对象
我们添加索引文档中不仅包含了数据还包含了元数据
比如我们为一个数据添加索引
文档中不仅有json的这些属性还包含红框中的值
文档的CRUD
http://127.0.0.1:9200/blogs/product/1
put 修改或者新增id为1的文档如果不存在新增 如果存在修改(1.找到旧文档json 2.修改他 3.删除旧文档 4.索引新文档)
delete则为删除
elasticsearch乐观锁
可以发现我们文档元数据有个version字段我们可以利用version字段进行乐观锁
修改失败 我们把版本换成4试试
成功
使用外部版本控制,比如使用我们主数据库表的版本字段添加则使用
http://127.0.0.1:9200/blogs/product/1?version=10&version_type=external
可以看到版本号变成了10 如果再次执行会抱错 因为不大于当前版本号 可以控制并发新增 导致的数据重复
文档局部更新
前面我们看到通过update请求也能实现更新,但是他是覆盖文档,删除原来的文档填入新的文档
post请求:http://127.0.0.1:9200/blogs/product/1/_update
参数
{ "doc":{ "productName":"测试修改", "videw":1 } }
相同字段会被更新 不存在的则添加到文档
使用groovy脚本更新
价格+1
post请求:http://127.0.0.1:9200/blogs/product/1/_update
参数
{ "script":"ctx._source.price+=1" }
ctx代表文档_source代表文档中的_source字段,因为我们的数据就是存在文档元数据的_source字段的
{ "_index": "blogs", "_type": "product", "_id": "1", "_version": 12, "_seq_no": 9, "_primary_term": 1, "found": true, "_source": { "productName": "测试修改", "price": 11, "remark": "不错的床垫", "tags": [ "家具", "床垫", "棉花" ], "videw": 1 } }
往tag中添加一个元素
post请求:http://127.0.0.1:9200/blogs/product/1/_update
参数:
{ "script":"ctx._source.tag+=newtag", "params":{ "newtag":"测试tag新增" } }
5.*之后会报错 Variable [newtag] is not defined
参数应改为:
{ "script":"ctx._source.tags.add(params.newtag)", "params":{ "newtag":"测试tag新增" } }
更新不存在的文档
适合计数器
post请求:http://127.0.0.1:9200/blogs/product/2/_update
参数
{ "script":"ctx._source.count+=1", "upsert":{ "count":"1" } }
第一次请求 将会为文档id为2的创建一个count属性 后续请求+1
更新重试
post请求:http://127.0.0.1:9200/blogs/product/2/_update?retry_on_conflict=5 更新失败后将会重试5此
批量操作
格式:
{
actionName:{metadata}\n
{requestBody}\n
.....
}
如我们同时要新增替换文档删除文档局部更新
post请求:http://127.0.0.1:9200/_bulk
{"create":{"_index":"blog","_type":"product","_id":5}} {"title":{"productName": "批量测试新增5","price": 10,"remark": "不错的床垫","tags": ["家具","床垫","棉花"],"videw": 1}} {"index":{"_index":"blog","_type":"product","_id":5}}\n {"title":{"productName": "批量测试新增","price": 10,"remark": "不错的床垫","tags": ["家具","床垫","棉花"],"videw": 1}} {"update":{"_index":"blog","_type":"product","_id":1,"_retry_on_conflict":3}} {"doc":{"title":{"productName": "批量测试修改" }}} {"delete":{"_index":"blog","_type":"product","_id":5}}}}
注意最后一个json需要有一个换行符
create创建文档 不存在则新增
index 创建文档不存在新增 存在覆盖
update 局部更新
delete删除
响应结果:
{ "took": 7, "errors": true, "items": [ { "create": { "_index": "blog", "_type": "product", "_id": "5", "status": 409, "error": { "type": "version_conflict_engine_exception", "reason": "[product][5]: version conflict, document already exists (current version [2])", "index_uuid": "CZ6SoctfQcCzXmVXFLdDuA", "shard": "1", "index": "blog" } } }, { "index": { "_index": "blog", "_type": "product", "_id": "5", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1, "status": 200 } }, { "update": { "_index": "blog", "_type": "product", "_id": "1", "status": 404, "error": { "type": "document_missing_exception", "reason": "[product][1]: document missing", "index_uuid": "CZ6SoctfQcCzXmVXFLdDuA", "shard": "3", "index": "blog" } } }, { "delete": { "_index": "blog", "_type": "product", "_id": "5", "_version": 4, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1, "status": 200 } } ] }
不需要重复指定所以呢和type可以在url带上索引和type上面就不用指定索引和type了
批量操作都是独立的并不是原子的 互不影响
索引文档原理
新建索引和删除文档
write操作都必须在主节点完成
1:请求到note1 操作P0分片数据
2.确定根据id shard=hash(routing)%number_of_parimary_shard 求出余数算出分片位置 转发请求到node3
3.node3执行请求 如果成功 复制分片在node1和node2 索引转发请求到node1和node2 如果都成功则修改生效
replication参数
第3步骤转发请求到复制分片是同步的 可以通过设置replication为async 则为异步 但是数据的准确性得不到保证 而且会导致每个请求都不等待复制返回 而导致的请求过载(不建议使用)、
consistency参数
在写入时必须有规定数量的分片可用才能写入 公式:
5.*以上貌似移除
timeout参数
分片副本不足的等待时间 默认一分钟
检索文档
1.node1接收到检索P0分片的请求
2.因为P0分片数据 在3个节点都存在
3.保证性能会通过负载均衡算法 算出转发到对应的节点
局部更新
1.node1接收到修改p0分片数据
2.转发到node3节点
3.node3节点 将分片文档的_source进行替换并重做索引
4.将请求转发大node1和node2处理 因为复制分片存放在node1和node2
根据条件更新
api地址:https://www.elastic.co/guide/en/elasticsearch/reference/6.2/docs-update-by-query.html
post:http://127.0.0.1:9200/[indexName]/_update_by_query
{ "query": { "bool": { "must": [{ "term": { "_id": "11" } }] } }, "script": { "inline": "ctx._source.name = params.name", "params": { "tags": "dd" }, "lang": "painless" } }
使用java api写法
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.must().add(QueryBuilders.termQuery("mdProductId", productCharacterStocksVo.getProductId())); boolQueryBuilder.must().add(QueryBuilders.termQuery("characterId", productCharacterStocksVo.getCharacterId())); boolQueryBuilder.must().add(QueryBuilders.termQuery("regionCode", productCharacterStocksVo.getRegionCode())); boolQueryBuilder.must().add(QueryBuilders.termQuery("ladingFactoryId", productCharacterStocksVo.getFactoryId())); updateByQueryRequest.setQuery(boolQueryBuilder); updateByQueryRequest.setScript(new Script( ScriptType.INLINE, "painless", "ctx._source.stockCount=" + productCharacterStocksVo.getSumCount(), Collections.emptyMap())); try { log.info(updateByQueryRequest.toString()); BulkByScrollResponse bulkByScrollResponse = eshlRestUtil.getClient().updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT); count = bulkByScrollResponse.getUpdated(); }catch (Exception e){ e.printStackTrace(); count=0L; }
根据条件删除
post:http://127.0.0.1:9200/test_latest/_delete_by_query
{ "query": { "bool": { "must": [{ "term": { "_id": "11" } }] } } }