Elasticsearch:运用 Java 更新 Elasticsearch 文档
2021年10月25日 | by mebius
在 Elasticsearch 的设计中,一般来说更新或者删除文档并不常见。这其中的原因最主要是 Elasticsearch 以搜索为主,针对大多数的文档来说,比如日志,指标,根本就不需要更新或者删除。更新文档通常会给 Elasticsearch 的性能带来一些影响,所以一般来说不建议频繁地更新文档。
在我的上一篇文章 “Elasticsearch:运用 Java 创建索引并写入数据” 中, 我详细地介绍了几种常见的通过 Java 创建 Elasticsearch 文档的方法。在今天的文章中,我来介绍几种如何更新 Elasticsearch 文档的方法。你也可以参阅我之前的另外一篇文章 “Elasticsearch:Java 运用示例”。
为了方便大家学习,我把最终的代码放在 github 上:https://github.com/liu-xiao-guo/ElasticsearchJava-update
首先,我们可以运用自己喜欢的 IDE 来创建一个简单的 Java 应用。有关 Maven pom.xml 的设计,请参阅我之前的文章 “Elasticsearch:运用 Java 创建索引并写入数据”。这里就不再赘述了。
在做练习之前,我们需要在 Kibana 中创建如下的两个文档:
PUT employees/_doc/1
{
"id": "1",
"sex": "male",
"age": 28,
"name": "Mark"
}
PUT employees/_doc/2
{
"id": "2",
"sex": "female",
"age": 22,
"name": "Grace"
}
通过上面的命令,我们创建了两个文档。它们的文档 _id 分别是 “1” 和 “2”。请注意这个 _id 和文档里的 id 字段是不一样的。
我们可以通过如下的命令来进行查询:
GET employees/_search
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : "1",
"sex" : "male",
"age" : 28,
"name" : "Mark"
}
},
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"id" : "2",
"sex" : "female",
"age" : 22,
"name" : "Grace"
}
}
]
}
}
修改文档
方法一:更新字段
我们可以使用如下的代码来进行更新:
// Method 1: update a sample string value
UpdateRequest updateRequest = new tgcodeUpdateRequest("employees", "1");
updateRequest.doc("age", 25);
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println("updated response id: "+updateResponse.getId());
在上面我们使用 update 接口,我把 _id 为 “1” 的文档的 age 字段值修改为 25。运行上面的代码:
updated response id: 1
上面显示被更新的文档 id。我们可以通过如下的命令来查看被修改的文档的值:
GET employees/_doc/1
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 2,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : "1",
"sex" : "male",
"age" : 25,
"name" : "Mark"
}
}
上面显示 age 被更新的值为 25 而不是之前的 28。
上面的命令实际上是在我之前的教程 “开始使用 Elasticsearch (1)” 中的如下命令:
POST employees/_update/1
{
"doc": {
"age": "25"
}
}
方法二:使用 Map 值更新一个特定的 id
// Method 2: Update id with particular Map values
Map updateMap = new HashMap();
updateMap.put("id","3");
updateMap.put("sex","male");
updateMap.put("age", 40);
updateMap.put("name", "liuxg");
updateMap.put("addtionalfield", "anything");
UpdateRequest request = new UpdateRequest("employees", "2").doc(updateMap);
UpdateResponse updateResponse2= client.update(request, RequestOptions.DEFAULT);
System.out.println("updated response id: "+updateResponse2.getId());
在上,我们使用 update 接口,但是使用 Map 值来进行更新。除了它更新已有的字段,我们还同时添加了一个叫做 additionalfield 的字段,并给它赋值为 anything。运行上面的代码,并通过 Kibana 来查看 _id 为 2 的文档:
GET employees/_doc/2
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "2",
"_version" : 2,
"_seq_no" : 3,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : "3",
"sex" : "male",
"age" : 40,
"name" : "liuxg",
"addtionalfield" : "anything"
}
}
我们可以看到各个字段都被更新了,并且有了新的字段。
方法三:使用 index API 来进行更新
// Method 3: Use index API to update
IndexRequest request3 = new IndexRequest("employees");
request3.id("1");
request3.source("age", 20);
IndexResponse indexResponse3 = client.index(request3, RequestOptions.DEFAULT);
System.out.println("response id: " + indexResponse3.getId());
System.out.println(indexResponse3.getResult().name());
在上面,我们使用 index API 接口来进行更新。特别值得指出的是,这个 index API 的使用将会删除之前所有的已有的文档字段,就好tgcode像在原有的 _id 里创建一个崭新的文档一样。
运行上面的代码,并通过如想的代码来进行查看:
GET employees/_doc/1
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"_seq_no" : 4,
"_primary_term" : 1,
"found" : true,
"_source" : {
"age" : 20
}
}
我们可以看到所有的其它字段都被删除了,只有有个字段。这个类似如在 Kibana 中使用如的命令:
POST employees/_doc/1
{
"age": 20
}
方法四:使用 Index API 来更新 – 通过 map
// Method 4: use index API to update via Map
Map updateMap4 = new HashMap();
updateMap4.put("field1","field1");
updateMap4.put("field2","field2");
updateMap4.put("field3", 30);
IndexRequest request4 = new IndexRequest("employees");
request4.id("2");
request4.source(updateMap4);
IndexResponse indexResponseUpdate4 = client.index(request4, RequestOptions.DEFAULT);
System.out.println("response id: " + indexResponseUpdate4.getId());
System.out.println(indexResponseUpdate4.getResult().name());
和上面的代码一样,所有之前关于这个 _id 的字段将被删除,并以 Map 中定义的字段来创建新的文档。运行上面的代码:
GET employees/_doc/2
{
"_index" : "employees",
"_type" : "_doc",
"_id"tgcode : "2",
"_version" : 3,
"_seq_no" : 11,
"_primary_term" : 1,
"found" : true,
"_source" : {
"field1" : "field1",
"field3" : 30,
"field2" : "field2"
}
}
我们可以看到所有的字段都被新的字段所代替。
方法五:通过 Java Polo object 来更新
我们需要设计一个 Employee 的 Java class,并通过如下代码来更新:
// Method 5: Use a PoJo Java object
Employee employee = new Employee("myid", "Martin");
IndexRequest indexRequest5 = new IndexRequest("employees");
indexRequest5.id("1");
indexRequest5.source(new ObjectMapper().writeValueAsString(employee), XContentType.JSON);
IndexResponse indexResponse5 = client.index(indexRequest5, RequestOptions.DEFAULT);
System.out.println("response id: "+indexResponse5.getId());
System.out.println("response name: "+indexResponse5.getResult().name());
运行上面的代码:
GET employees/_doc/1
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_version" : 12,
"_seq_no" : 16,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : "myid",
"name" : "Martin"
}
}
方法六:通过 updateByQuery 来更新
这个需要使用 Painless 脚本来进行更新:
// Method 6: Update it with UpdateByQuery
Map updateMap6 = new HashMap();
updateMap6.put("id","66");
updateMap6.put("name","Bill");
UpdateByQueryRequest updateByQueryRequest6 = new UpdateByQueryRequest("employees");
updateByQueryRequest6.setConflicts("proceed");
updateByQueryRequest6.setQuery(new TermQueryBuilder("_id", "1"));
Script script = new Script(ScriptType.INLINE, "painless","ctx._source = params", updateMap6);
updateByQueryRequest6.setScript(script);
try {
BulkByScrollResponse bulkResponse = client.updateByQuery(updateByQueryRequest6, RequestOptions.DEFAULT);
long totalDocs = bulkResponse.getTotal();
System.out.println("updated response id: "+totalDocs);
} catch (IOException e) {
e.printStackTrace();
}
运行上面的代码:
GET employees/_doc/1
{
"_index" : "employees",
"_type" : "_doc",
"_id" : "1",
"_version" : 16,
"_seq_no" : 22,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "Bill",
"id" : "66"
}
}
这个类似于如下的 Kibana 命令。如果你对这个不是很熟的话,请参阅 “开始使用 Elasticsearch (1)”:
POST employees/_update_by_query
{
"query": {
"term": {
"_id": {
"value": "1"
}
}
},
"script": {
"source": "ctx._source.id = params.id;ctx._source.name = params.name",
"lang": "painless",
"params": {
"id": "66",
"name": "Bill"
}
}
}
好了,今天的讲解就到这里。在今天的文章中,我介绍了几种最为常见的方法来更新一个已经存在的文章。希望对大家的开发有所启发。
文章来源于互联网:Elasticsearch:运用 Java 更新 Elasticsearch 文档
相关推荐: Elasticsearch:使用 Path Hierarchy Tokenizer 搜索层次结构
本文介绍了如何解决一个常见问题,该问题通常通过使用 Elasticsearch 中称为路径层次结构 tokenizer的功能来查看不同的解决方案,从而通过父/子关系或递归关系来解决。 你可以用这个覆解决什么用例? 在我们深入研究之前,让我们先了解一下使用案例!…