- elastic search支持list类型的数据存储ElasticSearch中支持的数据类型
假设我们有以下数据:
{
"_index": "school",
"_type": "student",
"_id": "id_4",
"_version": 1,
"_score": 1,
"_source": {
"name": "this name is name",
"id": 4,
"tags": [
"班长",
"学习委员",
"文艺委员"
]
}
}
可以看到在以上数据中tags为list类型,假设在一个业务场景中,我们需要对这个list中的值进行更新(删除或者添加),按照常规的操作方式,我们可能需要先取出tags的所有值,然后利用elastic search的Partial更新来更新tags的值。其实相比较与这种更新方式,es提供的构建Script来实现这种操作可能更加符合业务需求,如下:
1.建立一个TransPortClient
public class OldTransportClient {
private Logger logger = Logger.getLogger(OldTransportClient.class);
private TransportClient client;
private IndicesAdminClient adminClient;
@Value("${es.host}")
private String host;
@PostConstruct
@SuppressWarnings({ "unchecked", "resource" })
public synchronized TransportClient setupTransportClient() throws UnknownHostException {
if (client == null) {
Settings settings = Settings.builder().put("cluster.name", "ceiec-test")
.put("client.transport.sniff", true).build();
client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), 9300));
logger.info("====== transport client set up! =======");
}
return client;
}
public synchronized IndicesAdminClient setupAdminClient() {
if (client != null) {
if (adminClient == null) {
adminClient = client.admin().indices();
logger.info("===== admin client set up ======");
}
}else {
logger.error("transport client is not set up,please set up it!");
}
return adminClient;
}
}
2.新建一个Script
/**
* update item with array in elasticSearch
* @param index
* @param type
* @param id
* @param value
* @param delete : (default false)
* -----> true delete an element from array
* -----> false add an element to array
* @throws Exception
*/
public void updateExistList(String index,String type,String id,String field,String value,boolean isDelete) throws Exception{
client = oldclient.setupTransportClient();
Map<String,Object> params = new HashMap<>();
params.put(field,value);
String script_str;
if (isDelete){
script_str = "if (ctx._source."+field+".indexOf(params."+field+") != -1){" +
"ctx._source."+field+".remove(ctx._source."+field+".indexOf(params."+field+"))}";
}else {
//表示如果该doc不包含该字段,在该doc新建字段并赋值value,
//如果存在该字段,会比较传入的值是否存在于list中,如果不存在就添加
script_str = "if(!ctx._source.containsKey('"+field+"')){ctx._source."+field+"=[params."+field+"]}else{" +
"if (ctx._source."+field+".indexOf(params."+field+") == -1){ ctx._source."+field+".add(params."+field+")}}";
}
Script script = new Script(ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG,script_str,params);
logger.info("script:\n"+script);
UpdateResponse updateResponse = client.prepareUpdate(index,type,id)
.setScript(script)
.get();
System.out.println(updateResponse.status());
}
通过以上操作,我们就可以对es中的list数据进行增加和删除.
以上是针对es的list存储的是简单类型比如String,number等类型进行的操作,那么假如list里面存储的是Object类型该怎么做呢,现在有如下的数据:
{
"_index": "school",
"_type": "student",
"_id": "id_2",
"_version": 9,
"_score": 1,
"_source": {
"name": "this name is name",
"id": 2,
"tags": [
"班长",
"学习委员",
"文艺委员"
],
"permission": [
{
"user": "user1",
"name": "zhangsan2"
},
{
"user": "user2",
"name": "zhangsan2"
},
{
"user": "user3",
"name": "zhangsan3"
},
{
"user": "user3",
"name": "zhangsan3"
},
{
"user": "user4",
"name": "zhangsan3"
}
]
}
}
我们可以看到permission字段是存储着Object的list,那我们想更新其中的元素该怎么操作呢?
其实方法很类似,我们只需要构建不同的script就可以实现啦,如下:
/**
* @param index
* @param type
* @param id
* @param field 需更新的字段
* @param value
* @param delete : (default false)
* -----> true delete an element from array
* -----> false add an element to array
* @throws Exception
*/
public void updateExistListObject(String index,String type,String doc_id,Object o,String field,boolean isDelete) throws Exception{
client = oldclient.setupTransportClient();
Map<String,String> map = (Map<String, String>) o;
String property = (String) map.keySet().toArray()[0];
Map<String,Object> params = new HashMap<>();
params.put(field,o);
String script_str;
if (isDelete){
script_str = "for (int i=0;i<ctx._source."+field +".size();i++)" +
"{ if(ctx._source."+field+"[i]['"+property+"'] == params."+field+"."+property+")"+
"{ctx._source."+field+".remove(i)}}";
}else {
//表示如果该doc不包含该字段,在该doc新建字段并赋值value,
//如果存在该字段,会比较传入的对象是否存在于list中存在的对象相等,如果不相等就添加,相等就更新
script_str = "if(!ctx._source.containsKey('"+field+"'))" + "{ctx._source."+field+"=[params."+field+"]} " +
"else { for(int i=0; i<ctx._source."+ field +".size(); i++)"+
"{ if (ctx._source."+field+"[i]['"+property+ "'] != params."+ field+"."+property+")
{ctx._source."+field+".add(params."+field+");break;}}}";
}
Script script = new Script(ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG,script_str,params);
logger.info("script:\n"+script);
UpdateResponse updateResponse = client.prepareUpdate(index,type,doc_id)
.setScript(script)
.get();
System.out.println(updateResponse.status());
}
script可以实现相当复杂的功能,因此需要大家在实践中去构建符合自己业务逻辑的script。
网友评论