本文将只发表在CSDN网站上,不会上传到百度文库,更不会发表在pudn网站上,如果发现此文被人上传到百度文库用于牟利,或者被pudn爬虫爬去,请联系作者或者帮忙举报,谢谢。
索引
更新索引的mapping
//新增或修改_mapping中的字段
POST my_index_demo/_mapping
{
"properties":{
"newVersion":{
"type": "boolean"
}
}
}
向索引的字段中增加或修改newVersion字段。
通过查询更新文档
查询符合条件的文档,并新增字段newVersion,设置值为true,或者更新已有newVersion字段,设置为true。
POST my_index_demo/_update_by_query
{
"query": {
"bool": {
"must": [
{
"term": {
"labelField": {
"value": "blabla"
}
}
}
]
}
},
"script":{
"source":"ctx._source['newVersion']=true"
}
}
根据查询条件,将符合条件的文档,通过script中的source字段进行修改,比如这儿就是给没有newVersion的文档新增newVersion字段,并设置为true,或者将文档中已有的newVersion字段值改为true。注意,如果通过script增加了字段,这个字段如果在_mapping中没有,就不能通过这个字段进行检索,解决办法就是通过通过更新mapping来让这个字段被索引。
根据查询条件,删除文档中的字段:
POST my_index_demo/_update_by_query
{
"query": {
"bool": {
"must": [
{
"term": {
"_id": {
"value": "65006065497076723"
}
}
}
]
}
},
"script":{
"source":"ctx._source.remove('newVersion')"
}
}
上面的更新语句就是把_id字段满足条件的文档中的newVersion字段删除。
Painless脚本
创建脚本
POST _scripts/脚本名称 如:
POST _scripts/my_demo_script
{
"script" : {
"lang" : "painless",
"source" : """
boolean containsCityId = false;
if(doc["newVersion"].size() > 0 && doc["newVersion"].value){
List cityList =doc["cityIds"];
for(id in cityList){
if(params.cityIds.contains(id)){
containsCityId=true;
}
}
}
return containsCityId;
"""
}
}
创建了一个名称为my_demo_script的脚本,这样在后续查询的时候可以根据这个脚本名称引用脚本,而不用在DSL语句中内嵌大段的脚本,而且预先将脚本保存到ES中,可以预先编译,提高查询效率。
这段脚本的意思是如果文档中有newVersion这个字段,并且字段值为true的情况下,判断参数中的cityIds列表与ES文档中的cityIds是否有交集。
lang字段指出这个脚本是painless,因为ES支持多种脚本语言。
source内容是脚本,当脚本需要换行的时候用三个双引号"比较方便。
根据脚本查询
POST /my_index_demo/_search
{
"from": 0,
"size": 100,
"timeout": "100ms",
"query": {
"bool": {
"filter": [{
"term": {
"labeField": {
"value": "blabla",
"boost": 1.0
}
}
}, {
"script": {
"script": {
"id": "my_demo_script",
"params": {
"cityIds": ["5101","3201","3213"]
}
},
"boost": 1.0
}
}],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"_source": {
"includes": ["newVersion", "cityIds","labelField"],
"excludes": []
},
"sort": [{
"updateTime": {
"order": "asc"
}
}]
}
通过脚本名字和脚本需要的参数params进行查询。
脚本中判断某个字段是否存在
painless脚本从doc中获取字段的结果都是List类型,如果要判断文档中是否有某个字段可以用
doc[“字段名”].size() > 0 判断
如果判断文档中某个boolean类型字段值是否为true可以用
doc[“字段名”].value
刚才不是说,doc[“字段名”]返回的是List么,怎么能对List类型用.value取值呢?其实通过Elaticsearch的源码org.elasticsearch.index.fielddata.ScriptDocValues.Booleans#getValue可以看到获取value的时候,自动帮你获取List中的第一个元素了:
public static final class Booleans extends ScriptDocValues<Boolean> {
private final SortedNumericDocValues in;
private boolean[] values = new boolean[0];
private int count;
public Booleans(SortedNumericDocValues in) {
this.in = in;
}
@Override
public void setNextDocId(int docId) throws IOException {
if (in.advanceExact(docId)) {
resize(in.docValueCount());
for (int i = 0; i < count; i++) {
values[i] = in.nextValue() == 1;
}
} else {
resize(0);
}
}
/**
* Set the {@link #size()} and ensure that the {@link #values} array can
* store at least that many entries.
*/
protected void resize(int newSize) {
count = newSize;
values = grow(values, count);
}
public boolean getValue() {
// 自动帮我们获取List中的第一个元素了
return get(0);
}
@Override
public Boolean get(int index) {
if (count == 0) {
throw new IllegalStateException(
"A document doesn't have a value for a field! "
+ "Use doc[<field>].size()==0 to check if a document is missing a field!"
);
}
return values[index];
}
@Override
public int size() {
return count;
}
private static boolean[] grow(boolean[] array, int minSize) {
assert minSize >= 0 : "size must be positive (got " + minSize + "): likely integer overflow?";
if (array.length < minSize) {
return Arrays.copyOf(array, ArrayUtil.oversize(minSize, 1));
} else return array;
}
}