Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Скрипты ›Как писать скрипты

Скрипты, кэширование и скорость поиска

Elasticsearch выполняет ряд оптимизаций, чтобы использование скриптов было максимально быстрым. Важная оптимизация — кэш скриптов. Компилированный скрипт помещается в кэш, чтобы запросы, ссылающиеся на этот скрипт, не несли затрат на компиляцию.

Размер кэша важен. Кэш скриптов должен быть достаточно большим, чтобы содержать все скрипты, к которым пользователи могут обращаться одновременно.

Если вы видите большое количество вытеснений из кэша скриптов и увеличивающееся количество компиляций в статистике узлов, возможно, кэш слишком мал.

Все скрипты кэшируются по умолчанию, поэтому их нужно перекомпилировать только при обновлениях. По умолчанию у скриптов нет временного ограничения кэша. Вы можете изменить это поведение, используя параметр script.cache.expire. Используйте параметр script.cache.max_size для настройки размера кэша.

Размер скриптов ограничен 65 535 байтами. Установите значение script.max_size_in_bytes, чтобы увеличить этот мягкий лимит. Если ваши скрипты очень большие, рассмотрите использование родного движка скриптов.

Улучшение скорости поиска

Скрипты невероятно полезны, но они не могут использовать структуры индексов Elasticsearch или связанные с ними оптимизации. Эта взаимосвязь иногда приводит к замедлению скорости поиска.

Если вы часто используете скрипты для преобразования индексированных данных, вы можете ускорить поиск, преобразуя данные во время загрузки (индексации) вместо этого. Однако это часто приводит к замедлению скорости индексации. Давайте рассмотрим практический пример, чтобы проиллюстрировать, как можно увеличить скорость поиска.

При выполнении поисков часто сортируются результаты по сумме двух значений. Например, рассмотрим индекс под названием my_test_scores, содержащий данные о результатах тестов. Этот индекс содержит два поля типа long:

  • math_score
  • verbal_score

Вы можете выполнить запрос со скриптом, который суммирует эти значения. В этом подходе нет ничего плохого, но запрос будет медленнее, потому что вычисление скрипта происходит как часть запроса. Следующий запрос возвращает документы, где grad_year равно 2099, и сортирует результаты по результату вычисления скрипта.

resp = client.search(
    index="my_test_scores",
    query={
        "term": {
            "grad_year": "2099"
        }
    },
    sort=[
        {
            "_script": {
                "type": "number",
                "script": {
                    "source": "doc['math_score'].value + doc['verbal_score'].value"
                },
                "order": "desc"
            }
        }
    ],
)
print(resp)
response = client.search(
  index: 'my_test_scores',
  body: {
    query: {
      term: {
        grad_year: '2099'
      }
    },
    sort: [
      {
        _script: {
          type: 'number',
          script: {
            source: "doc['math_score'].value + doc['verbal_score'].value"
          },
          order: 'desc'
        }
      }
    ]
  }
)
puts response
const response = await client.search({
  index: "my_test_scores",
  query: {
    term: {
      grad_year: "2099",
    },
  },
  sort: [
    {
      _script: {
        type: "number",
        script: {
          source: "doc['math_score'].value + doc['verbal_score'].value",
        },
        order: "desc",
      },
    },
  ],
});
console.log(response);
GET /my_test_scores/_search
{
  "query": {
    "term": {
      "grad_year": "2099"
    }
  },
  "sort": [
    {
      "_script": {
        "type": "number",
        "script": {
          "source": "doc['math_score'].value + doc['verbal_score'].value"
        },
        "order": "desc"
      }
    }
  ]
}

Если вы ищете в небольшом индексе, то включение скрипта в ваш поисковый запрос может быть хорошим решением. Если вы хотите ускорить поиск, вы можете выполнить это вычисление во время загрузки и индексировать сумму в отдельное поле.

Сначала добавим новое поле в индекс под названием total_score, которое будет содержать сумму значений полей math_score и verbal_score.

resp = client.indices.put_mapping(
    index="my_test_scores",
    properties={
        "total_score": {
            "type": "long"
        }
    },
)
print(resp)
response = client.indices.put_mapping(
  index: 'my_test_scores',
  body: {
    properties: {
      total_score: {
        type: 'long'
      }
    }
  }
)
puts response
const response = await client.indices.putMapping({
  index: "my_test_scores",
  properties: {
    total_score: {
      type: "long",
    },
  },
});
console.log(response);
PUT /my_test_scores/_mapping
{
  "properties": {
    "total_score": {
      "type": "long"
    }
  }
}

Далее, используйте пайплайн загрузки, содержащий процессор скриптов, для вычисления суммы math_score и verbal_score и индексации её в поле total_score.

resp = client.ingest.put_pipeline(
    id="my_test_scores_pipeline",
    description="Calculates the total test score",
    processors=[
        {
            "script": {
                "source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
            }
        }
    ],
)
print(resp)
response = client.ingest.put_pipeline(
  id: 'my_test_scores_pipeline',
  body: {
    description: 'Calculates the total test score',
    processors: [
      {
        script: {
          source: 'ctx.total_score = (ctx.math_score + ctx.verbal_score)'
        }
      }
    ]
  }
)
puts response
const response = await client.ingest.putPipeline({
  id: "my_test_scores_pipeline",
  description: "Calculates the total test score",
  processors: [
    {
      script: {
        source: "ctx.total_score = (ctx.math_score + ctx.verbal_score)",
      },
    },
  ],
});
console.log(response);
PUT _ingest/pipeline/my_test_scores_pipeline
{
  "description": "Calculates the total test score",
  "processors": [
    {
      "script": {
        "source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
      }
    }
  ]
}

Для обновления существующих данных используйте этот пайплайн для переиндексации документов из my_test_scores в новый индекс под названием my_test_scores_2.

resp = client.reindex(
    source={
        "index": "my_test_scores"
    },
    dest={
        "index": "my_test_scores_2",
        "pipeline": "my_test_scores_pipeline"
    },
)
print(resp)
response = client.reindex(
  body: {
    source: {
      index: 'my_test_scores'
    },
    dest: {
      index: 'my_test_scores_2',
      pipeline: 'my_test_scores_pipeline'
    }
  }
)
puts response
const response = await client.reindex({
  source: {
    index: "my_test_scores",
  },
  dest: {
    index: "my_test_scores_2",
    pipeline: "my_test_scores_pipeline",
  },
});
console.log(response);
POST /_reindex
{
  "source": {
    "index": "my_test_scores"
  },
  "dest": {
    "index": "my_test_scores_2",
    "pipeline": "my_test_scores_pipeline"
  }
}

Продолжайте использовать пайплайн для индексации новых документов в my_test_scores_2.

resp = client.index(
    index="my_test_scores_2",
    pipeline="my_test_scores_pipeline",
    document={
        "student": "kimchy",
        "grad_year": "2099",
        "math_score": 1200,
        "verbal_score": 800
    },
)
print(resp)
response = client.index(
  index: 'my_test_scores_2',
  pipeline: 'my_test_scores_pipeline',
  body: {
    student: 'kimchy',
    grad_year: '2099',
    math_score: 1200,
    verbal_score: 800
  }
)
puts response
const response = await client.index({
  index: "my_test_scores_2",
  pipeline: "my_test_scores_pipeline",
  document: {
    student: "kimchy",
    grad_year: "2099",
    math_score: 1200,
    verbal_score: 800,
  },
});
console.log(response);
POST /my_test_scores_2/_doc/?pipeline=my_test_scores_pipeline
{
  "student": "kimchy",
  "grad_year": "2099",
  "math_score": 1200,
  "verbal_score": 800
}

Эти изменения замедляют процесс индексации, но позволяют ускорить поиск. Вместо использования скрипта, вы можете сортировать поиски, выполненные на my_test_scores_2, используя поле total_score. Ответ практически мгновенный! Хотя этот процесс замедляет загрузку, он значительно ускоряет запросы во время поиска.

resp = client.search(
    index="my_test_scores_2",
    query={
        "term": {
            "grad_year": "2099"
        }
    },
    sort=[
        {
            "total_score": {
                "order": "desc"
            }
        }
    ],
)
print(resp)
response = client.search(
  index: 'my_test_scores_2',
  body: {
    query: {
      term: {
        grad_year: '2099'
      }
    },
    sort: [
      {
        total_score: {
          order: 'desc'
        }
      }
    ]
  }
)
puts response
const response = await client.search({
  index: "my_test_scores_2",
  query: {
    term: {
      grad_year: "2099",
    },
  },
  sort: [
    {
      total_score: {
        order: "desc",
      },
    },
  ],
});
console.log(response);
GET /my_test_scores_2/_search
{
  "query": {
    "term": {
      "grad_year": "2099"
    }
  },
  "sort": [
    {
      "total_score": {
        "order": "desc"
      }
    }
  ]
}

© 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/scripts-and-search-speed.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API