正在加载

访问文档字段和特殊变量

Elastic Stack Serverless

根据脚本的使用位置,它将有权访问某些特殊变量和文档字段。

updateupdate-by-queryreindex API 中使用的脚本将有权访问 ctx 变量,该变量公开

ctx._source
访问文档 _source 字段
ctx.op
应应用于文档的操作:indexdelete
ctx._index
访问 文档元数据字段,其中一些可能是只读的。

这些脚本无权访问 doc 变量,必须使用 ctx 才能访问它们操作的文档。

除了 脚本字段(每个搜索命中执行一次)之外,在搜索和聚合中使用的脚本将为可能匹配查询或聚合的每个文档执行一次。 根据您拥有的文档数量,这可能意味着数百万或数十亿次执行:这些脚本需要快速!

可以使用 doc-values_source 字段存储字段从脚本访问字段值,以下将对它们进行说明。

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

这是一个在 function_score 查询中使用脚本来更改每个文档的相关性 _score 的示例

 PUT my-index-000001/_doc/1?refresh {
  "text": "quick brown fox",
  "popularity": 1
}

PUT my-index-000001/_doc/2?refresh
{
  "text": "quick fox",
  "popularity": 5
}

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

script_score 查询中使用的脚本可以访问 _termStats 变量,该变量提供有关子查询中词项的统计信息。

在以下示例中,_termStatsscript_score 查询中使用,以检索 text 字段中词项 quickbrownfox 的平均词频

 PUT my-index-000001/_doc/1?refresh {
  "text": "quick brown fox"
}

PUT my-index-000001/_doc/2?refresh
{
  "text": "quick fox"
}

GET my-index-000001/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "script": {
        "source": "_termStats.termFreq().getAverage()"
      }
    }
  }
}
  1. 用于推断词项统计信息中考虑的字段和词项的子查询。
  2. 该脚本使用 _termStats 计算查询中词项的平均文档频率。

_termStats 提供以下函数来处理词项统计信息

  • uniqueTermsCount:返回查询中唯一词项的总数。 此值在所有文档中均相同。
  • matchedTermsCount:返回当前文档中匹配的查询词项的计数。
  • docFreq:提供查询中词项的文档频率统计信息,指示有多少文档包含每个词项。 此值在所有文档中均一致。
  • totalTermFreq:提供所有文档中词项的总频率,表示每个词项在整个语料库中出现的频率。 此值在所有文档中均一致。
  • termFreq:返回当前文档中查询词项的频率,显示每个词项在该文档中出现的频率。
返回聚合统计信息的函数

docFreqtermFreqtotalTermFreq 函数返回表示子查询的所有词项的统计信息的对象。

统计信息提供对以下方法的支持

getAverage():返回指标的平均值。 getMin():返回指标的最小值。 getMax():返回指标的最大值。 getSum():返回指标值的总和。 getCount():返回指标计算中包含的词项的计数。

需要 Painless 语言

仅在使用 Painless 脚本语言时,_termStats 变量才可用。

从脚本访问字段值最快、最有效的方式是使用 doc['field_name'] 语法,该语法从 doc values 中检索字段值。 Doc values 是一种列式字段值存储,默认情况下在所有字段上启用,但 analyzed text fields 除外。

 PUT my-index-000001/_doc/1?refresh {
  "cost_price": 100
}

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

Doc-values 只能返回“简单”字段值,例如数字、日期、地理点、词项等,或者如果字段是多值字段,则返回这些值的数组。 它不能返回 JSON 对象。

缺少字段

如果映射中缺少 field,则 doc['field'] 将引发错误。 在 painless 中,可以首先使用 doc.containsKey('field') 进行检查,以保护对 doc 映射的访问。 遗憾的是,无法在 expression 脚本中检查映射中是否存在该字段。

Doc values 和文本字段

如果启用了 fielddata,则 doc['field'] 语法也可用于 analyzed text fields,但请注意:在 text 字段上启用 fielddata 需要将所有词项加载到 JVM 堆中,这在内存和 CPU 方面都可能非常昂贵。 从脚本访问 text 字段很少有意义。

可以使用 _source.field_name 语法访问文档 _source_source 作为映射映射加载,因此可以访问对象字段中的属性,例如 _source.name.first

首选 doc-values 而不是 _source

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

在为搜索结果中的前十个命中生成 脚本字段时使用 _source 是有意义的,但对于其他搜索和聚合用例,始终首选使用 doc values。

例如

 PUT my-index-000001 {
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text"
      },
      "last_name": {
        "type": "text"
      }
    }
  }
}

PUT my-index-000001/_doc/1?refresh
{
  "first_name": "Barry",
  "last_name": "White"
}

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

存储字段 — 在映射中显式标记为 "store": true 的字段 — 可以使用 _fields['field_name'].value_fields['field_name'] 语法访问

 PUT my-index-000001 {
  "mappings": {
    "properties": {
      "full_name": {
        "type": "text",
        "store": true
      },
      "title": {
        "type": "text",
        "store": true
      }
    }
  }
}

PUT my-index-000001/_doc/1?refresh
{
  "full_name": "Alice Ball",
  "title": "Professor"
}

GET my-index-000001/_search
{
  "script_fields": {
    "name_with_title": {
      "script": {
        "lang": "painless",
        "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
      }
    }
  }
}
存储字段 vs _source

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

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

© . All rights reserved.