Доступ к полям документов и специальным переменным
В зависимости от места использования скрипта, он будет иметь доступ к определённым специальным переменным и полям документа.
Скрипты обновления
Скрипт, используемый в API обновления, обновления по запросу или повторной индексации, будет иметь доступ к переменной ctx, которая предоставляет:
| | Доступ к полю документа |
| | Операцию, которая должна быть применена к документу: |
| | Доступ к полям метаданных документа, некоторые из которых могут быть только для чтения. |
Эти скрипты не имеют доступа к переменной doc и должны использовать ctx для доступа к документам, над которыми они работают.
Скрипты поиска и агрегации
За исключением скриптовых полей, которые выполняются один раз на каждый результат поиска, скрипты, используемые в поиске и агрегациях, будут выполняться один раз для каждого документа, который может соответствовать запросу или агрегации. В зависимости от количества документов, это может означать миллионы или миллиарды выполнений: эти скрипты должны быть быстрыми!
Значения полей могут быть получены из скрипта с помощью doc-значений, поля _source или сохранённых полей, каждое из которых описано ниже.
Доступ к рейтингу документа в скрипте
Скрипты, используемые в function_score запросе, в сортировке на основе скриптов или в агрегациях, имеют доступ к переменной _score, которая представляет текущий релевантный рейтинг документа.
Вот пример использования скрипта в function_score запросе для изменения релевантности _score каждого документа:
resp = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"text": "quick brown fox",
"popularity": 1
},
)
print(resp)
resp1 = client.index(
index="my-index-000001",
id="2",
refresh=True,
document={
"text": "quick fox",
"popularity": 5
},
)
print(resp1)
resp2 = client.search(
index="my-index-000001",
query={
"function_score": {
"query": {
"match": {
"text": "quick brown fox"
}
},
"script_score": {
"script": {
"lang": "expression",
"source": "_score * doc['popularity']"
}
}
}
},
)
print(resp2) response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
text: 'quick brown fox',
popularity: 1
}
)
puts response
response = client.index(
index: 'my-index-000001',
id: 2,
refresh: true,
body: {
text: 'quick fox',
popularity: 5
}
)
puts response
response = client.search(
index: 'my-index-000001',
body: {
query: {
function_score: {
query: {
match: {
text: 'quick brown fox'
}
},
script_score: {
script: {
lang: 'expression',
source: "_score * doc['popularity']"
}
}
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
text: "quick brown fox",
popularity: 1,
},
});
console.log(response);
const response1 = await client.index({
index: "my-index-000001",
id: 2,
refresh: "true",
document: {
text: "quick fox",
popularity: 5,
},
});
console.log(response1);
const response2 = await client.search({
index: "my-index-000001",
query: {
function_score: {
query: {
match: {
text: "quick brown fox",
},
},
script_score: {
script: {
lang: "expression",
source: "_score * doc['popularity']",
},
},
},
},
});
console.log(response2); 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, которая предоставляет статистическую информацию о терминах в запросе подзапроса.
В следующем примере _termStats используется в script_score запросе для получения средней частоты терминов для терминов quick, brown и fox в поле text:
resp = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"text": "quick brown fox"
},
)
print(resp)
resp1 = client.index(
index="my-index-000001",
id="2",
refresh=True,
document={
"text": "quick fox"
},
)
print(resp1)
resp2 = client.search(
index="my-index-000001",
query={
"script_score": {
"query": {
"match": {
"text": "quick brown fox"
}
},
"script": {
"source": "_termStats.termFreq().getAverage()"
}
}
},
)
print(resp2) const response = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
text: "quick brown fox",
},
});
console.log(response);
const response1 = await client.index({
index: "my-index-000001",
id: 2,
refresh: "true",
document: {
text: "quick fox",
},
});
console.log(response1);
const response2 = await client.search({
index: "my-index-000001",
query: {
script_score: {
query: {
match: {
text: "quick brown fox",
},
},
script: {
source: "_termStats.termFreq().getAverage()",
},
},
},
});
console.log(response2); 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()"
}
}
}
} | Подзапрос, используемый для определения поля и терминов, рассматриваемых в статистике терминов. | |
| Скрипт вычисляет среднюю частоту документов для терминов в запросе, используя |
_termStats предоставляет доступ к следующим функциям для работы со статистикой терминов:
-
uniqueTermsCount: Возвращает общее количество уникальных терминов в запросе. Это значение одинаково для всех документов. -
matchedTermsCount: Возвращает количество терминов запроса, совпавших в текущем документе. -
docFreq: Предоставляет статистику частоты документов для терминов в запросе, указывающую, сколько документов содержат каждый термин. Это значение постоянно для всех документов. -
totalTermFreq: Предоставляет общую частоту терминов по всем документам, представляющую, насколько часто каждый термин встречается во всем корпусе. Это значение постоянно для всех документов. -
termFreq: Возвращает частоту терминов запроса в текущем документе, показывая, как часто каждый термин появляется в этом документе.
Функции, возвращающие агрегированную статистику
Функции docFreq, termFreq и totalTermFreq возвращают объекты, представляющие статистику по всем терминам подзапроса.
Статистика поддерживает следующие методы:
getAverage(): Возвращает среднее значение метрики. getMin(): Возвращает минимальное значение метрики. getMax(): Возвращает максимальное значение метрики. getSum(): Возвращает сумму значений метрики. getCount(): Возвращает количество терминов, включенных в вычисление метрики.
Необходимость языка Painless
Переменная _termStats доступна только при использовании языка сценариев Painless.
Значения документов
Наиболее быстрый и эффективный способ доступа к значению поля из скрипта — использование синтаксиса doc['field_name'], который извлекает значение поля из doc-значений. Doc-значения — это хранилище значений полей в столбцах, включённое по умолчанию для всех полей, за исключением анализированных text полей.
resp = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"cost_price": 100
},
)
print(resp)
resp1 = client.search(
index="my-index-000001",
script_fields={
"sales_price": {
"script": {
"lang": "expression",
"source": "doc['cost_price'] * markup",
"params": {
"markup": 0.2
}
}
}
},
)
print(resp1) response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
cost_price: 100
}
)
puts response
response = client.search(
index: 'my-index-000001',
body: {
script_fields: {
sales_price: {
script: {
lang: 'expression',
source: "doc['cost_price'] * markup",
params: {
markup: 0.2
}
}
}
}
}
)
puts response const response = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
cost_price: 100,
},
});
console.log(response);
const response1 = await client.search({
index: "my-index-000001",
script_fields: {
sales_price: {
script: {
lang: "expression",
source: "doc['cost_price'] * markup",
params: {
markup: 0.2,
},
},
},
},
});
console.log(response1); 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-значения могут возвращать только «простые» значения полей, такие как числа, даты, гео-точки, термины и т. д., или массивы этих значений, если поле многозначное. Они не могут возвращать JSON-объекты.
Отсутствующие поля
doc['field'] вызовет ошибку, если field отсутствует в схеме. В painless можно сначала выполнить проверку с помощью doc.containsKey('field'), чтобы защитить доступ к карте doc. К сожалению, нет способа проверить наличие поля в схеме в скрипте expression.
Doc-значения и text поля
Синтаксис doc['field'] также может использоваться для анализированных text полей, если fielddata включен, но ОСТОРОЖНО: включение fielddata для text поля требует загрузки всех терминов в кучу JVM, что может быть очень затратно с точки зрения памяти и ЦП. Доступ к text полям из скриптов редко имеет смысл.
Документ _source
К документу _source можно получить доступ, используя синтаксис _source.field_name. _source загружается как карта карт, поэтому к свойствам в полях объектов можно получить доступ, например, как _source.name.first.
Предпочитайте doc-значения полю _source
Доступ к полю _source намного медленнее, чем использование doc-значений. Поле _source оптимизировано для возврата нескольких полей на результат, в то время как doc-значения оптимизированы для доступа к значению определенного поля во многих документах.
Использование _source имеет смысл при создании скриптового поля для первых десяти результатов поиска, но для других случаев поиска и агрегаций всегда предпочитайте doc-значения.
Например:
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"first_name": {
"type": "text"
},
"last_name": {
"type": "text"
}
}
},
)
print(resp)
resp1 = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"first_name": "Barry",
"last_name": "White"
},
)
print(resp1)
resp2 = client.search(
index="my-index-000001",
script_fields={
"full_name": {
"script": {
"lang": "painless",
"source": "params._source.first_name + ' ' + params._source.last_name"
}
}
},
)
print(resp2) response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
first_name: {
type: 'text'
},
last_name: {
type: 'text'
}
}
}
}
)
puts response
response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
first_name: 'Barry',
last_name: 'White'
}
)
puts response
response = client.search(
index: 'my-index-000001',
body: {
script_fields: {
full_name: {
script: {
lang: 'painless',
source: "params._source.first_name + ' ' + params._source.last_name"
}
}
}
}
)
puts response const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
first_name: {
type: "text",
},
last_name: {
type: "text",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
first_name: "Barry",
last_name: "White",
},
});
console.log(response1);
const response2 = await client.search({
index: "my-index-000001",
script_fields: {
full_name: {
script: {
lang: "painless",
source: "params._source.first_name + ' ' + params._source.last_name",
},
},
},
});
console.log(response2); 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']:
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"full_name": {
"type": "text",
"store": True
},
"title": {
"type": "text",
"store": True
}
}
},
)
print(resp)
resp1 = client.index(
index="my-index-000001",
id="1",
refresh=True,
document={
"full_name": "Alice Ball",
"title": "Professor"
},
)
print(resp1)
resp2 = client.search(
index="my-index-000001",
script_fields={
"name_with_title": {
"script": {
"lang": "painless",
"source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
}
}
},
)
print(resp2) response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
full_name: {
type: 'text',
store: true
},
title: {
type: 'text',
store: true
}
}
}
}
)
puts response
response = client.index(
index: 'my-index-000001',
id: 1,
refresh: true,
body: {
full_name: 'Alice Ball',
title: 'Professor'
}
)
puts response
response = client.search(
index: 'my-index-000001',
body: {
script_fields: {
name_with_title: {
script: {
lang: 'painless',
source: "params._fields['title'].value + ' ' + params._fields['full_name'].value"
}
}
}
}
)
puts response const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
full_name: {
type: "text",
store: true,
},
title: {
type: "text",
store: true,
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "my-index-000001",
id: 1,
refresh: "true",
document: {
full_name: "Alice Ball",
title: "Professor",
},
});
console.log(response1);
const response2 = await client.search({
index: "my-index-000001",
script_fields: {
name_with_title: {
script: {
lang: "painless",
source:
"params._fields['title'].value + ' ' + params._fields['full_name'].value",
},
},
},
});
console.log(response2); 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"
}
}
}
} Сохраненные и _source
Поле _source — это просто специальное сохраненное поле, поэтому производительность аналогична производительности других сохраненных полей. Поле _source предоставляет доступ к исходному телу документа, которое было проиндексировано (включая возможность различать значения null от пустых полей, массивы с одним значением от простых скаляров и т. д.).
Единственный случай, когда использование сохраненных полей вместо поля _source действительно оправдано, — это когда _source очень велико, и доступ к нескольким небольшим сохраненным полям оказывается менее затратным, чем доступ ко всему _source.
© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/modules-scripting-fields.html