https://yq.aliyun.com/articles/368786
JAVA_API 增删改查
public class es {
private Logger logger = LoggerFactory.getLogger(es.class);
public final static String HOST = "192.168.1.140";
public final static int PORT = 9300; //http请求的端口是9200,客户端是9300
private TransportClient client = null;
String index = "zhouls";//设置索引库
String type = "emp";//设置类型
//索引index(四种格式:json,map,bean,es helper)
// @Before
public void getConnect() throws Exception {
client = new PreBuiltTransportClient(Settings.EMPTY).addTransportAddresses(new InetSocketTransportAddress(InetAddress.getByName(HOST), PORT));
logger.info("连接信息:" + client.toString());
}
/**
* Index API
* 3、Elasticsearch索引库的创建
*/
@Test
public void addIndex0() throws IOException {
/** 在一个main方法中,我们首先需要用TransportClient的子类PreBuiltTransportClient去连接我们的elasticsearch,注意java连接es的端口号是9300。
文本添加的jsonBuilder是以对象的开始(startObject)和结束(endObject)为标志,在其中以属性field的方式添加。其中添加的需要有name和value。
内容填写完毕后,需要增加到elasticsearch中,使用索引IndexResponse类型的prepareIndex方法,参数为地址索引和类型索引,将文件添加是setSource(对象).get()。
这样就将文件添加到了elasticsearch中,并可以查询了。*/
XContentBuilder builder = jsonBuilder()
.startObject()
.field("first_name", "gou gou")
.field("last_name", "smith")
.field("about", "trying out Elasticsearch")
.field("interests", "music,act")
.endObject();
IndexResponse response = client.prepareIndex("megacorp", "employee").setSource(builder).get();
System.out.println(response);
client.close();
}
/**
* 创建索引库
* 需求:创建一个索引库为:msg消息队列,类型为:tweet,id为1
* 索引库的名称必须为小写
*/
@Test
public void addIndex1() throws IOException {
IndexResponse response = client.prepareIndex("msg", "tweet", "1")
.setSource(XContentFactory.jsonBuilder()
.startObject().field("userName", "张三")
.field("sendDate", new Date())
.field("msg", "你好李四")
.endObject()).get();
logger.info("索引名称:" + response.getIndex() + "\n类型:" + response.getType() + "\n文档ID:" + response.getId());
client.close();
}
/**
* 4、向索引库中添加json字符串
*/
@Test
public void addIndexJson() {
String jsonStr = "{" +
"\"userName\":\"张三\"," +
"\"sendDate\":\"2017-11-30\"," +
"\"msg\":\"你好李四\"" +
"}";
IndexResponse response = client.prepareIndex("weixin", "tweet").setSource(jsonStr, XContentType.JSON).get();
logger.info("json索引名称:" + response.getIndex() + "\njson类型:" + response.getType() + "\njson文档ID:" + response.getId() + "\n当前实例json状态:" + response.getType());
}
/**
* 5、向索引库添加一个Map集合
*/
@Test
public void addIndexMap() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("userName", "张三");
map.put("sendDate", new Date());
map.put("msg", "你好李四");
IndexResponse response = client.prepareIndex("momo", "tweet").setSource(map).get();
logger.info("map索引名称:" + response.getIndex() + "\n map类型:" + response.getType() + "\n map文档ID:" + response.getId());
}
/**
* 6、向索引库添加JsonObject
* 传递json对象
*/
@Test
public void addIndexJsonObject() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("userName", "张三");
jsonObject.addProperty("sendDate", "2017-11-23");
jsonObject.addProperty("msg", "你好李四");
IndexResponse response = client.prepareIndex("qq", "tweet").setSource(jsonObject, XContentType.JSON).get();
logger.info("jsonObject索引名称:" + response.getIndex() + "\n jsonObject类型:" + response.getType() + "\n jsonObject文档ID:" + response.getId());
}
@Test
public void test6() throws Exception {//传入一个对象到index索引库,这里是Person对象
Person person = new Person();
person.setName("mack");
person.setAge(20);
//如果直接传入一个person对象会报错,java.lang.IllegalArgumentException,必须把对象转换成一个Json字符串,使用jackson依赖
//IndexResponse indexResponse = transportClient.prepareIndex(index, type, "9").setSource(person).get();
ObjectMapper objectMapper = new ObjectMapper();
String writeValueAsString = objectMapper.writeValueAsString(person);
IndexResponse indexResponse = transportClient.prepareIndex(index, type, "3")
.setSource(writeValueAsString)
.get();
// IndexResponse indexResponse = transportClient.prepareIndex(index, type, "3").setSource(objectMapper.writeValueAsString(person)).get();
System.out.println(indexResponse.getVersion());
}
/**
* 7、从索引库获取数据
*/
@Test
public void getData1() {
GetResponse getResponse = client.prepareGet("msg", "tweet", "1").get(); //查询id为1的数据
logger.info("索引库的数据:" + getResponse.getSourceAsString());
}
/**
* 全文查询
*/
@Test
public void getHits() {
SearchResponse response = client.prepareSearch("megacorp").setTypes("employee").get();
System.out.print(response);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit sh : hits) {
System.out.println(sh.getSourceAsString());
// Map<String, Object> data = sh.getSourceAsMap();
// String full_name = data.get("first_name") + "." + data.get("last_name");
// String age = data.get("age").toString();
// String about = data.get("about").toString();
//
// List<String> interests = (List<String>) data.get("interests");
// System.out.println(full_name + "\t" + age + "\t" + about);
// for (String like : interests) {
// System.out.println(like);
// }
}
client.close();
}
/**
* 模糊查询
*/
@Test
public void termsQuery() {
SearchResponse response = client.prepareSearch("megacorp").setTypes("employee").setQuery(
QueryBuilders.termsQuery("last_name", "smith")
//单条信息的查询,不适合在聚合情况下的查询,需要知道vlaue包含的值
).get();
System.out.println(response);
}
/**
* 聚合查询
*/
@Test
public void Aggregation() {
SearchResponse response = client.prepareSearch("megacorp").setTypes("employee").addAggregation(
AggregationBuilders.terms("all_interests").field("interests").subAggregation(
AggregationBuilders.avg("avg_age").field("age")
)
).execute().actionGet();
System.out.println(response);
client.close();
}
/**
* 更新索引库数据
*/
@Test
public void updateData() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("userName", "王五");
jsonObject.addProperty("sendDate", "2008-08-08");
jsonObject.addProperty("msg", "你好,张三,好久不见");
UpdateResponse updateResponse = client.prepareUpdate("msg", "tweet", "1").setDoc(jsonObject.toString(), XContentType.JSON).get();
logger.info("updateResponse索引名称:" + updateResponse.getIndex() + "\n updateResponse类型:" + updateResponse.getType() + "\n updateResponse文档ID:" + updateResponse.getId());
}
/**
* 根据索引名称,类别,文档ID 删除索引库的数据
*/
@Test
public void deleteData() {
DeleteResponse deleteResponse = client.prepareDelete("msg", "tweet", "4").get(); //删除id为4的数据
logger.info("deleteResponse索引名称:" + deleteResponse.getIndex() + "\n deleteResponse类型:" + deleteResponse.getType() + "\n deleteResponse文档ID:" + deleteResponse.getId());
}
/**
* count 取总数 类似于sql中的 select count(1) from table;
* 求总数
* 类似于mysql中的select count(*)
*/
@Test
public void test11() throws Exception {
long count = client.prepareCount(index)//查找索引库中的数据个数
.setTypes(type).get().getCount();
System.out.println(count);
}
/**
* bulk 批量操作 适合初始化数据的时候使用,提高效率
* 批量操作,执行多个命令
*/
@Test
public void bulk() throws Exception {
BulkRequestBuilder prepareBulk = client.prepareBulk();
//for循环执行----
//index请求
IndexRequest indexRequest = new IndexRequest(index, type, "10");
indexRequest.source("{\"name\":\"zhangsan\",\"age\":17}");
//delete请求
DeleteRequest deleteRequest = new DeleteRequest(index, type, "1");
// bulkProcessor.add(/* Your requests */);
prepareBulk.add(indexRequest);//bulkBuilder中可以添加多个操作,这里一个是建立索引的操作.
prepareBulk.add(deleteRequest);//一个是删除的操作
//执行 bulk
BulkResponse bulkResponse = prepareBulk.get();
if (bulkResponse.hasFailures()) {//批量操作中可能有的操作会出现问题,这个地方对操作失败的处理
//有执行失败的
BulkItemResponse[] items = bulkResponse.getItems();
for (BulkItemResponse bulkItemResponse : items) {
//获取失败信息,并打印
System.out.println(bulkItemResponse.getFailureMessage());
}
} else {
System.out.println("全部执行成功!");
}
}
}
Elasticsearch Java API 6.2(文档API)
文档API
本节描述以下CRUD API:
单文档的API
- Index API
- Get API
- Delete API
- Update API
多文档API
- Multi Get API
- Bulk API
- Reindex API
- Update By Query API
- Delete By Query API
注意
所有 CRUD API都是单索引 API,索引参数接受单个索引名,或指向单个索引的别名
Index API
index API允许将类型化的JSON文档索引到特定的索引中,并使其可搜索。
生成JSON文档
生成JSON文档有几种不同的方法:
- 手动的(也就是你自己)使用原生
byte[]
或作为String
- 使用一个
Map
,该Map
将自动转换为它的JSON等效项 - 使用第三方库对bean(如Jackson)进行序列化
- 使用内置的助手
XContentFactory.jsonBuilder()
在内部,每个类型被转换为byte[]
(像String
被转换为byte[]
),因此,如果对象已经以这种形式存在,那么就使用它,jsonBuilder是高度优化的JSON生成器,它直接构造一个byte[]
。
自己动手
这里没有什么困难,但是请注意,您必须根据日期格式对日期进行编码。
String json = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
使用Map
Map是一个键:值对集合,它表示一个JSON结构:
Map<String, Object> json = new HashMap<String, Object>();
json.put("user","kimchy");
json.put("postDate",new Date());
json.put("message","trying out Elasticsearch");
将bean序列化
可以使用Jackson将bean序列化为JSON,请将Jackson Databind添加到您的项目中,然后,您可以使用ObjectMapper
来序列化您的bean:
import com.fasterxml.jackson.databind.*;
// instance a json mapper
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
// generate json
byte[] json = mapper.writeValueAsBytes(yourbeaninstance);
使用Elasticsearch助手
Elasticsearch提供了内置的助手来生成JSON内容。
import static org.elasticsearch.common.xcontent.XContentFactory.*;
XContentBuilder builder = jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "trying out Elasticsearch")
.endObject()
注意,您还可以使用startArray(String)
和endArray()
方法添加数组,顺便说一下,field
方法接受许多对象类型,您可以直接传递数字、日期甚至其他XContentBuilder
对象。
如果需要查看生成的JSON内容,可以使用string()
方法。
String json = builder.string();
索引文档
下面的示例将JSON文档索引为一个名为twitter的索引,其类型为tweet, id值为1:
import static org.elasticsearch.common.xcontent.XContentFactory.*;
IndexResponse response = client.prepareIndex("twitter", "tweet", "1")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "trying out Elasticsearch")
.endObject()
)
.get();
注意,您还可以将文档索引为JSON字符串,并且不需要提供ID:
String json = "{" +
"\"user\":\"kimchy\"," +
"\"postDate\":\"2013-01-30\"," +
"\"message\":\"trying out Elasticsearch\"" +
"}";
IndexResponse response = client.prepareIndex("twitter", "tweet")
.setSource(json, XContentType.JSON)
.get();
IndexResponse
对象会给你一个响应:
// Index name
String _index = response.getIndex();
// Type name
String _type = response.getType();
// Document ID (generated or not)
String _id = response.getId();
// Version (if it's the first time you index this document, you will get: 1)
long _version = response.getVersion();
// status has stored current instance statement.
RestStatus status = response.status();
有关索引操作的更多信息,请查看REST索引文档
Get API
get API允许根据索引的id从索引中获取类型化的JSON文档,下面的示例从一个名为twitter的索引中获取JSON文档,该索引的类型名为tweet, id值为1:
GetResponse response = client.prepareGet("twitter", "tweet", "1").get();
有关get操作的更多信息,请查看REST get文档。
Delete API
delete API允许基于id从特定索引中删除类型化的JSON文档,下面的示例从名为twitter的索引中删除JSON文档,该索引的类型名为tweet, id值为1:
DeleteResponse response = client.prepareDelete("twitter", "tweet", "1").get();
Delete By Query API
通过查询删除的API可以根据查询结果删除给定的一组文档:
BulkByScrollResponse response = DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
.filter(QueryBuilders.matchQuery("gender", "male"))
.source("persons")
.get();
long deleted = response.getDeleted();
QueryBuilders.matchQuery("gender", "male")
(查询)source("persons")
(索引)get()
(执行操作)response.getDeleted()
(被删除的文档数)
由于这是一个长时间运行的操作,如果您希望异步执行,可以调用execute
而不是get
,并提供如下监听器:
DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
.filter(QueryBuilders.matchQuery("gender", "male"))
.source("persons")
.execute(new ActionListener<BulkByScrollResponse>() {
@Override
public void onResponse(BulkByScrollResponse response) {
long deleted = response.getDeleted();
}
@Override
public void onFailure(Exception e) {
// Handle the exception
}
});
Update API
您可以创建一个UpdateRequest
并将其发送给客户端:
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index("index");
updateRequest.type("type");
updateRequest.id("1");
updateRequest.doc(jsonBuilder()
.startObject()
.field("gender", "male")
.endObject());
client.update(updateRequest).get();
也可以使用prepareUpdate()
方法:
client.prepareUpdate("ttl", "doc", "1")
.setScript(new Script("ctx._source.gender = \"male\"" , ScriptService.ScriptType.INLINE, null, null))
.get();
client.prepareUpdate("ttl", "doc", "1")
.setDoc(jsonBuilder()
.startObject()
.field("gender", "male")
.endObject())
.get();
Script()
(你的脚本,它也可以是本地存储的脚本名)setDoc()
(将合并到现有的文档)
注意,您不能同时提供脚本和doc
使用脚本更新
update API允许基于提供的脚本更新文档:
UpdateRequest updateRequest = new UpdateRequest("ttl", "doc", "1")
.script(new Script("ctx._source.gender = \"male\""));
client.update(updateRequest).get();
通过合并文档更新
update API还支持传递一个部分文档合并到现有文档中(简单的递归合并,内部合并对象,取代核心的“键/值”和数组),例如:
UpdateRequest updateRequest = new UpdateRequest("index", "type", "1")
.doc(jsonBuilder()
.startObject()
.field("gender", "male")
.endObject());
client.update(updateRequest).get();
Upsert
也有对Upsert的支持,如果文档不存在,则使用upsert元素的内容索引新的doc:
IndexRequest indexRequest = new IndexRequest("index", "type", "1")
.source(jsonBuilder()
.startObject()
.field("name", "Joe Smith")
.field("gender", "male")
.endObject());
UpdateRequest updateRequest = new UpdateRequest("index", "type", "1")
.doc(jsonBuilder()
.startObject()
.field("gender", "male")
.endObject())
.upsert(indexRequest);
client.update(updateRequest).get();
如果文档不存在,将添加indexRequest中的文档。
如果文件index/type/1已经存在,我们将在此操作后获得如下文件:
{
"name" : "Joe Dalton",
"gender": "male"
}
"gender": "male"
(此字段由更新请求添加)
如果不存在,我们将有一份新文件:
{
"name" : "Joe Smith",
"gender": "male"
}
Multi Get API
multi get API允许根据文档的index、type和id获取文档列表:
MultiGetResponse multiGetItemResponses = client.prepareMultiGet()
.add("twitter", "tweet", "1")
.add("twitter", "tweet", "2", "3", "4")
.add("another", "type", "foo")
.get();
for (MultiGetItemResponse itemResponse : multiGetItemResponses) {
GetResponse response = itemResponse.getResponse();
if (response.isExists()) {
String json = response.getSourceAsString();
}
}
add("twitter", "tweet", "1")
(通过单一id)add("twitter", "tweet", "2", "3", "4")
(或以相同index/type的id列表)add("another", "type", "foo")
(你也可以从另一个索引中得到)MultiGetItemResponse itemResponse : multiGetItemResponses
(迭代结果集)response.isExists()
(您可以检查文档是否存在)response.getSourceAsString()
(访问_source字段)
有关multi get操作的更多信息,请查看剩余的multi get文档
Bulk API
bulk API允许在一个请求中索引和删除多个文档,这里有一个示例用法:
import static org.elasticsearch.common.xcontent.XContentFactory.*;
BulkRequestBuilder bulkRequest = client.prepareBulk();
// either use client#prepare, or use Requests# to directly build index/delete requests
bulkRequest.add(client.prepareIndex("twitter", "tweet", "1")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "trying out Elasticsearch")
.endObject()
)
);
bulkRequest.add(client.prepareIndex("twitter", "tweet", "2")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "another post")
.endObject()
)
);
BulkResponse bulkResponse = bulkRequest.get();
if (bulkResponse.hasFailures()) {
// process failures by iterating through each bulk response item
}
使用Bulk处理器
BulkProcessor
类提供了一个简单的接口,可以根据请求的数量或大小自动刷新bulk操作,或者在给定的时间之后。
要使用它,首先创建一个BulkProcessor
实例:
import org.elasticsearch.action.bulk.BackoffPolicy;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
BulkProcessor bulkProcessor = BulkProcessor.builder(
client,
new BulkProcessor.Listener() {
@Override
public void beforeBulk(long executionId,
BulkRequest request) { ... }
@Override
public void afterBulk(long executionId,
BulkRequest request,
BulkResponse response) { ... }
@Override
public void afterBulk(long executionId,
BulkRequest request,
Throwable failure) { ... }
})
.setBulkActions(10000)
.setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
.setFlushInterval(TimeValue.timeValueSeconds(5))
.setConcurrentRequests(1)
.setBackoffPolicy(
BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
.build();
-
beforeBulk()
- 此方法在执行bulk之前被调用,例如,您可以通过
request.numberOfActions()
查看numberOfActions
- 此方法在执行bulk之前被调用,例如,您可以通过
-
afterBulk(...BulkResponse response)
- 此方法在执行bulk之后被调用,例如,您可以通过
response.hasFailures()
检查是否存在失败请求
- 此方法在执行bulk之后被调用,例如,您可以通过
-
afterBulk(...Throwable failure)
- 当bulk失败并引发一个可抛出对象时,将调用此方法
-
setBulkActions(10000)
- 我们希望每10,000个请求就执行一次bulk
-
setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
- 我们希望每5MB就flush一次
-
setFlushInterval(TimeValue.timeValueSeconds(5))
- 无论请求的数量是多少,我们都希望每5秒flush一次
-
setConcurrentRequests(1)
- 设置并发请求的数量,值为0意味着只允许执行一个请求,在积累新的bulk请求时,允许执行一个值为1的并发请求
-
setBackoffPolicy()
- 设置一个自定义的备份策略,该策略最初将等待100ms,以指数形式增加并重试三次,当一个或多个bulk项目请求以
EsRejectedExecutionException
失败时,将尝试重试,该异常表明用于处理请求的计算资源太少,要禁用backoff,请传递BackoffPolicy.noBackoff()
- 设置一个自定义的备份策略,该策略最初将等待100ms,以指数形式增加并重试三次,当一个或多个bulk项目请求以
默认情况下,BulkProcessor
:
- bulkActions设置为1000
- bulkSize设置为5mb
- 不设置flushInterval
- 将concurrentrequest设置为1,这意味着flush操作的异步执行
- 将backoffPolicy设置为一个指数备份,8次重试,启动延时为50ms,总等待时间约为5.1秒
添加请求
然后您可以简单地将您的请求添加到BulkProcessor
:
bulkProcessor.add(new IndexRequest("twitter", "tweet", "1").source(/* your doc here */));
bulkProcessor.add(new DeleteRequest("twitter", "tweet", "2"));
关闭Bulk Processor
当所有的文档都被加载到BulkProcessor
,可以使用awaitClose
或close
方法进行关闭:
bulkProcessor.awaitClose(10, TimeUnit.MINUTES);
或
bulkProcessor.close();
如果通过设置flushInterval来调度其他计划的flush,这两种方法都将flush所有剩余的文档,并禁用所有其他计划flush。如果并发请求被启用,那么awaitClose
方法等待指定的超时以完成所有bulk请求,然后返回true
,如果在所有bulk请求完成之前指定的等待时间已经过去,则返回false
,close
方法不等待任何剩余的批量请求完成并立即退出。
在测试中使用Bulk Processor
如果您正在使用Elasticsearch运行测试,并且正在使用BulkProcessor来填充数据集,那么您最好将并发请求的数量设置为0,以便以同步方式执行批量的flush操作:
BulkProcessor bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() { /* Listener methods */ })
.setBulkActions(10000)
.setConcurrentRequests(0)
.build();
// Add your requests
bulkProcessor.add(/* Your requests */);
// Flush any remaining requests
bulkProcessor.flush();
// Or close the bulkProcessor if you don't need it anymore
bulkProcessor.close();
// Refresh your indices
client.admin().indices().prepareRefresh().get();
// Now you can start searching!
client.prepareSearch().get();
Update By Query API
updateByQuery最简单的用法是在不更改源的情况下更新索引中的每个文档,这种用法允许获取一个新属性或另一个在线映射更改。
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("source_index").abortOnVersionConflict(false);
BulkByScrollResponse response = updateByQuery.get();
对updateByQuery API的调用从获取索引快照开始,索引使用内部版本控制找到任何文档。
注意
当一个文档在快照的时间和索引请求过程之间发生变化时,会发生版本冲突。
当版本匹配时,updateByQuery更新文档并增加版本号。
所有更新和查询失败都会导致updateByQuery中止,这些故障可以从BulkByScrollResponse#getIndexingFailures
方法中获得,任何成功的更新仍然存在,并且不会回滚,当第一次失败导致中止时,响应包含由失败的bulk请求生成的所有失败。
为了防止版本冲突导致updateByQuery中止,请设置abortOnVersionConflict(false)
,第一个示例之所以这样做,是因为它试图获取在线映射更改,而版本冲突意味着在相同时间开始updateByQuery和试图更新文档的冲突文档。这很好,因为该更新将获取在线映射更新。
UpdateByQueryRequestBuilder API支持过滤更新的文档,限制要更新的文档总数,并使用脚本更新文档:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("source_index")
.filter(QueryBuilders.termQuery("level", "awesome"))
.size(1000)
.script(new Script(ScriptType.INLINE, "ctx._source.awesome = 'absolutely'", "painless", Collections.emptyMap()));
BulkByScrollResponse response = updateByQuery.get();
UpdateByQueryRequestBuilder还允许直接访问用于选择文档的查询,您可以使用此访问来更改默认的滚动大小,或者以其他方式修改对匹配文档的请求。
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("source_index")
.source().setSize(500);
BulkByScrollResponse response = updateByQuery.get();
您还可以将大小与排序相结合以限制文档的更新:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("source_index").size(100)
.source().addSort("cat", SortOrder.DESC);
BulkByScrollResponse response = updateByQuery.get();
除了更改文档的_source
字段外,还可以使用脚本更改操作,类似于Update API:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("source_index")
.script(new Script(
ScriptType.INLINE,
"if (ctx._source.awesome == 'absolutely) {"
+ " ctx.op='noop'"
+ "} else if (ctx._source.awesome == 'lame') {"
+ " ctx.op='delete'"
+ "} else {"
+ "ctx._source.awesome = 'absolutely'}",
"painless",
Collections.emptyMap()));
BulkByScrollResponse response = updateByQuery.get();
在Update API中,可以设置ctx.op
的值来更改执行的操作:
-
noop
- 如果您的脚本没有做任何更改,设置
ctx.op = "noop"
,updateByQuery操作将从更新中省略该文档,这种行为增加了响应主体中的noop计数器。
- 如果您的脚本没有做任何更改,设置
-
delete
- 如果您的脚本决定必须删除该文档,设置
ctx.op = "delete"
,删除将在响应主体中已删除的计数器中报告。
- 如果您的脚本决定必须删除该文档,设置
将ctx.op
设置为任何其他值都会产生错误,在ctx
中设置任何其他字段都会产生错误。
这个API不允许您移动它所接触的文档,只是修改它们的源,这是故意的!我们没有规定要把文件从原来的位置移走。
您也可以同时对多个索引和类型执行这些操作,类似于search API:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("foo", "bar").source().setTypes("a", "b");
BulkByScrollResponse response = updateByQuery.get();
如果提供路由值,则进程将路由值复制到滚动查询,将进程限制为与路由值匹配的碎片:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source().setRouting("cat");
BulkByScrollResponse response = updateByQuery.get();
updateByQuery也可以通过指定这样的pipeline来使用ingest节点:
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.setPipeline("hurray");
BulkByScrollResponse response = updateByQuery.get();
使用Task API
您可以使用Task API获取所有正在运行的update-by-query请求的状态:
ListTasksResponse tasksList = client.admin().cluster().prepareListTasks()
.setActions(UpdateByQueryAction.NAME).setDetailed(true).get();
for (TaskInfo info: tasksList.getTasks()) {
TaskId taskId = info.getTaskId();
BulkByScrollTask.Status status = (BulkByScrollTask.Status) info.getStatus();
// do stuff
}
使用上面所示的TaskId,您可以直接查找任务:
GetTaskResponse get = client.admin().cluster().prepareGetTask(taskId).get();
使用Cancel Task API
任何查询更新都可以使用Task Cancel API取消:
// Cancel all update-by-query requests
client.admin().cluster().prepareCancelTasks().setActions(UpdateByQueryAction.NAME).get().getTasks();
// Cancel a specific update-by-query request
client.admin().cluster().prepareCancelTasks().setTaskId(taskId).get().getTasks();
使用list tasks API查找taskId的值。
取消请求通常是一个非常快速的过程,但可能要花费几秒钟的时间,task status API继续列出任务,直到取消完成。
Rethrottling
在正在运行的更新中,使用_rethrottle API更改requests_per_second
的值:
RethrottleAction.INSTANCE.newRequestBuilder(client)
.setTaskId(taskId)
.setRequestsPerSecond(2.0f)
.get();
使用list tasks API查找taskId的值。
与updateByQuery API一样,requests_per_second
的值可以是任何正值的浮点值来设置节流的级别,或者Float.POSITIVE_INFINITY
禁用节流。requests_per_second
值加快进程立即生效,减慢查询的requests_per_second
值在完成当前批处理后生效,以防止滚动超时。
Reindex API
详情见reindex API
BulkByScrollResponse response = ReindexAction.INSTANCE.newRequestBuilder(client)
.destination("target_index")
.filter(QueryBuilders.matchQuery("category", "xzy"))
.get();
还可以提供查询来筛选应该从源索引到目标索引的哪些文档
JestClient实现对ElasticSearch的操作
JestClient通过写json来实现对ElasticSearch的操作,
使用jestClient比较明显的一个优势就是,不用因为es的版本升级导致API发生改变而更改代码。
import com.andon.jestclientdemo.domain.BaseModel;
import com.google.gson.JsonObject;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.*;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;
import io.searchbox.indices.settings.GetSettings;
import io.searchbox.indices.settings.UpdateSettings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
@Service
public class ESService {
private static final Logger LOG = LoggerFactory.getLogger(ESService.class);
@Resource
JestClient jestClient;
/**
* 发送json查询
*/
SearchResult jsonSearch(String json, String indexName, String typeName) {
Search search = new Search.Builder(json).addIndex(indexName).addType(typeName).build();
try {
return jestClient.execute(search);
} catch (Exception e) {
LOG.warn("index:{}, type:{}, search again!! error = {}", indexName, typeName, e.getMessage());
sleep(100);
return jsonSearch(json, indexName, typeName);
}
}
/**
* 批量写入
*/
public <T extends BaseModel> void bulkIndex(List<T> list, String indexName) {
Bulk.Builder bulk = new Bulk.Builder();
for (T o : list) {
Index index = new Index.Builder(o).id(o.getPK()).index(indexName).type(o.getType()).build();
bulk.addAction(index);
}
try {
jestClient.execute(bulk.build());
} catch (IOException e) {
LOG.warn("bulkIndex again!! error={} index={}", e.getMessage(), indexName);
sleep(100);
bulkIndex(list, indexName);
}
}
/**
* 新增或者更新文档
*/
public <T> void insertOrUpdateDocumentById(T o, String index, String type, String uniqueId) {
Index.Builder builder = new Index.Builder(o);
builder.id(uniqueId);
builder.refresh(true);
Index indexDoc = builder.index(index).type(type).build();
try {
jestClient.execute(indexDoc);
} catch (IOException e) {
LOG.warn("insertOrUpdateDocumentById again!! error={} id={}", e.getMessage(), uniqueId);
sleep(100);
insertOrUpdateDocumentById(o, index, type, uniqueId);
}
}
/**
* 根据主键id删除文档
*/
public void deleteDocumentById(String index, String type, String id) {
Delete delete = new Delete.Builder(id).index(index).type(type).build();
try {
jestClient.execute(delete);
} catch (IOException e) {
LOG.warn("deleteDocumentById again!! error={} id={}", e.getMessage(), id);
sleep(100);
deleteDocumentById(index, type, id);
}
}
/**
* 根据主键id获取文档
*/
public <T> T getDocumentById(T object, String index, String id) {
Get get = new Get.Builder(index, id).build();
T o = null;
try {
JestResult result = jestClient.execute(get);
o = (T) result.getSourceAsObject(object.getClass());
} catch (IOException e) {
LOG.warn("getDocumentById again!! error={} id=");
sleep(100);
getDocumentById(object, index, id);
}
return o;
}
private void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
LOG.error("Thread sleep failure!! error={}", e.getMessage());
}
}
/**
* 创建index
*/
public void createIndex(String index) {
try {
JestResult jestResult = jestClient.execute(new CreateIndex.Builder(index).build());
System.out.println("createIndex:{}" + jestResult.isSucceeded());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 删除index
*/
public void deleteIndex(String index) {
try {
JestResult jestResult = jestClient.execute(new DeleteIndex.Builder(index).build());
System.out.println("deleteIndex result:{}" + jestResult.isSucceeded());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 设置index的mapping(设置数据类型和分词方式)
*/
public void createIndexMapping(String index, String type, String mappingString) {
// mappingString为拼接好的json格式的mapping串
PutMapping.Builder builder = new PutMapping.Builder(index, type, mappingString);
try {
JestResult jestResult = jestClient.execute(builder.build());
System.out.println("createIndexMapping result:{}" + jestResult.isSucceeded());
if (!jestResult.isSucceeded()) {
System.err.println("settingIndexMapping error:{}" + jestResult.getErrorMessage());
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取index的mapping
*/
public String getMapping(String indexName, String typeName) {
GetMapping.Builder builder = new GetMapping.Builder();
builder.addIndex(indexName).addType(typeName);
try {
JestResult result = jestClient.execute(builder.build());
return result.getSourceAsObject(JsonObject.class).toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取索引index设置setting
*/
public boolean getIndexSettings(String index) {
try {
JestResult jestResult = jestClient.execute(new GetSettings.Builder().addIndex(index).build());
System.out.println(jestResult.getJsonString());
return jestResult.isSucceeded();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* 更改索引index设置setting
*/
public boolean updateIndexSettings(String index) {
String source;
XContentBuilder mapBuilder = null;
try {
mapBuilder = XContentFactory.jsonBuilder();
mapBuilder.startObject().startObject("index").field("max_result_window", "1000000").endObject().endObject();
source = mapBuilder.string();
JestResult jestResult = jestClient.execute(new UpdateSettings.Builder(source).build());
System.out.println(jestResult.getJsonString());
return jestResult.isSucceeded();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}