需求背景:当浏览文档时使此文档的浏览数+1;利用ElsaticSearch的脚本更新可以灵活的实现该需求
如果使用sql应对以上需求,我们应该很简单的就可以写出
update news_bak.newsBase set browseCount = browseCount + 1 where id="5bf29a4f086899caed65e6bc"
在es中对应以上sql逻辑的代码,如下
POST /news_bak/newsBase/5bf29a4f086899caed65e6bc/_update
{
"script": {
"inline": "ctx._source.browseCount += params.incr",
"params": {
"incr":1
}
}
}
其中,news_bak为对应的index,newsBase为对应的type. 另外,注意一点,在引用变量时,以前的版本直接引用变量名即可,而Elasticsearch5.0以上的版本取参数需要使用==params.{参数名}==,这是语法上的更新,如果跟以前一样,直接这样使用:
POST /news_bak/newsBase/5bf29a4f086899caed65e6bc/_update
{
"script": {
"inline": "ctx._source.browseCount += incr",
"params": {
"incr":1
}
}
}
则会报错,提示我们出现异常==illegal_argument_exception==,告诉我们原因是==Variable [incr] is not defined.==,参数 incr 未定义
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[Sn0hpRC][192.168.8.53:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "compile error",
"script_stack": [
"... x._source.browseCount += incr",
" ^---- HERE"
],
"script": "ctx._source.browseCount += incr",
"lang": "painless",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Variable [incr] is not defined."
}
}
},
"status": 400
}
所以我们需要注意一下自己的Elasticsearch==版本==
接下来是使用Spring的ElasticSearchTemplate来进行操作,方法以及进行了封装 主要代码如下: model:
@Document(indexName = "news_bak", type = "newsBase")
public class NewsBase implements Serializable {
@Id
private String id;
private String author;
private String browsingVolume;
private String headImg;
private String content;
... 下面省略
}
EsUtil里面封装了对应的方法
/**
* 提供es的工具类
*
* @author neo_chen
* @version Ver 1.0 2018/11/16 新增
* @Package
*/
public class EsUtil {
/**
* 在es的对应字段上追加对应的值
* @param id 要追加的文档的id
* @param clazz 文档对应Class对象
* @param addFiled 要追加的字段
* @param addParam 要追加的值
* @return UpdateQuery
* @eg 给这个文档的browseCount字段值+1
* POST /#{index}/#{type}/#{id}/_update
* {
* "script": {
* "inline": "ctx._source.browseCount += params.incr",
* "params": {
* "incr":1
* }
* }
* }
*/
public static <T>UpdateQuery filedValueAdd(String id, Class<T> clazz, String addFiled, Object addParam) {
//构建UpdataRequest对象
UpdateRequest updateRequest = new UpdateRequest();
//设置参数
Map<String, Object> params = new HashMap<>();
params.put("incr", addParam);
//构架Script对象,这里注意是 org.elasticsearch.script.Script
Script script = new Script(Script.DEFAULT_SCRIPT_TYPE, "painless", "ctx._source." + addFiled + " += params.incr", params);
updateRequest.script(script);
//构架UpdateQueryBuilder 对象
UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder();
//设置要修改的_id
updateQueryBuilder.withId(id);
//设置updateRequest对象
updateQueryBuilder.withUpdateRequest(updateRequest);
//设置 class 对象,其实这里用class对象就是要区实体类标注的 index 和 type 也可以直接设置index 和 type
/*
//可以替换成
updateQueryBuilder.withIndexName("your index");
updateQueryBuilder.withType("yourType");
*/
updateQueryBuilder.withClass(clazz);
UpdateQuery build = updateQueryBuilder.build();
return build;
}
}
调用:
@Service(value = "newsBaseService")
public class NewsBaseServiceImpl implements NewsBaseService {
@Autowired
private ElasticsearchTemplate esTemplate;
@Override
public Long incrBrowse(String id) throws Exception {
// id 为要改变的资讯id,NewsBase.class类,要修改的字段为browseCount,在原来的基础上+1
UpdateQuery build = EsUtil.filedValueAdd(id, NewsBase.class, "browseCount", 1);
UpdateResponse update = esTemplate.update(build);
return null;
}
}