原英文版地址: https://www.elastic.co/guide/en/elasticsearch/reference/7.7/modules-scripting-fields.html, 原文档版权归 www.elastic.co 所有
本地英文版地址: ../en/modules-scripting-fields.html

访问文档字段和特殊变量

根据脚本的使用场合,它可以访问某些特殊变量和文档字段。

更新(update)脚本

更新(update)按查询更新(update-by-query)重新索引(reindex)中使用的脚本可以访问变量ctx,该变量公开了以下属性:

ctx._source

访问 _source字段

ctx.op

应该应用于文档的操作:indexdelete

ctx._index

访问文档元字段,其中一些可能是只读的。

搜索和聚合脚本

除了每个搜索命中执行一次的脚本字段(script fields)之外,搜索和聚合中使用的脚本将对每个可能匹配查询或聚合的文档执行一次。 取决于你有多少文档,这可能意味着数百万或数十亿次执行:这些脚本需要运行得很快!

可以使用文档值(doc-values)、 源(_source)字段存储的字段(stored fields)从脚本中访问字段值,下面会对他们进行一一说明。

在脚本内获取文档的得分

function_score查询、基于脚本的排序聚合中使用的脚本可以访问代表文档当前相关性分数的_score变量。

下面是一个在function_score查询中使用脚本来改变每个文档的相关性评分(_score)的示例:

PUT my_index/_doc/1?refresh
{
  "text": "quick brown fox",
  "popularity": 1
}

PUT my_index/_doc/2?refresh
{
  "text": "quick fox",
  "popularity": 5
}

GET my_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "script_score": {
        "script": {
          "lang": "expression",
          "source": "_score * doc['popularity']"
        }
      }
    }
  }
}

文档值(doc values)

到目前为止,从脚本中访问字段值最快最有效的方法是使用doc['field_name']语法,该语法从文档值(doc values)中检索字段值。 文档值是按列式字段值存储的,默认情况下,除了analyzed text字段(会被分析的字段)之外,所有字段都启用该存储方式。

PUT my_index/_doc/1?refresh
{
  "cost_price": 100
}

GET my_index/_search
{
  "script_fields": {
    "sales_price": {
      "script": {
        "lang":   "expression",
        "source": "doc['cost_price'] * markup",
        "params": {
          "markup": 0.2
        }
      }
    }
  }
}

文档值只能返回“简单”的字段值,如numbers、dates、geo-points、terms等,如果字段是多值的,则返回这些值的数组。它不能返回JSON对象。

缺失的字段

如果映射中缺少fielddoc['field']将会引发错误。 在painless下,可以首先使用doc.containsKey('field')进行检查,以防止访问doc的映射。 不幸的是,没有办法在expression脚本中检查映射中是否存在该字段。

文档值和text字段



如果启用了fielddata,则doc['field']语法也可以用于分析的(analyzed)text字段,但是请注意:在text字段上启用 fielddata 需要将所有的词项加载到JVM堆中,这在内存和CPU方面的开销都很大。 在脚本中访问text字段没有什么意义。

文档的源(_source)

可以使用_source.field_name语法访问文档的源(_source)。 _source作为映射的映射加载,因此对象字段中的属性可以像_source.name.first这样来访问。

首选文档值(doc-values)而非_source



访问_source字段比使用文档值(doc-values)要慢得多。 _source字段针对每个结果返回几个字段进行了优化,而文档值(doc values)针对访问许多文档中特定字段的值进行了优化。

当从搜索结果中为前10个命中生成脚本字段(script field)时,使用_source是有意义的,但是对于其他搜索和聚合用例,总是首选使用文档值(doc values)。

例如:

PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text"
      },
      "last_name": {
        "type": "text"
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "first_name": "Barry",
  "last_name": "White"
}

GET my_index/_search
{
  "script_fields": {
    "full_name": {
      "script": {
        "lang": "painless",
        "source": "params._source.first_name + ' ' + params._source.last_name"
      }
    }
  }
}

存储的字段(stored fields)

存储字段(Stored fields)-在映射中明确标记为"store": true的字段-可以使用_fields['field_name'].value_fields['field_name']语法进行访问:

PUT my_index
{
  "mappings": {
    "properties": {
      "full_name": {
        "type": "text",
        "store": true
      },
      "title": {
        "type": "text",
        "store": true
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "full_name": "Alice Ball",
  "title": "Professor"
}

GET my_index/_search
{
  "script_fields": {
    "name_with_title": {
      "script": {
        "lang": "painless",
        "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
      }
    }
  }
}

存储的(stored)与源(_source)



_source字段只是一个特殊的存储的字段,所以性能和其他存储字段差不多。 _source提供了对被索引的原始文档主体的访问(包括区分null值与空字段、单值数组与普通标量等的能力)。

只有当_source非常大,并且访问一些小的存储字段比访问整个_source成本更低时,使用存储字段而不是_source字段才有意义。