スクリプト、キャッシュ、および検索速度

Elasticsearchは、スクリプトをできるだけ速く使用できるように、いくつかの最適化を行います。重要な最適化の1つはスクリプトキャッシュです。コンパイルされたスクリプトはキャッシュに置かれ、スクリプトを参照するリクエストはコンパイルペナルティを受けません。

キャッシュのサイズは重要です。スクリプトキャッシュは、ユーザーが同時にアクセスする必要があるすべてのスクリプトを保持できるだけの大きさであるべきです。

node statsでスクリプトキャッシュの排出が多く、コンパイルの数が増加している場合、キャッシュが小さすぎる可能性があります。

すべてのスクリプトはデフォルトでキャッシュされ、更新が発生したときのみ再コンパイルが必要です。デフォルトでは、スクリプトには時間ベースの有効期限はありません。この動作は、script.cache.expire設定を使用して変更できます。script.cache.max_size設定を使用してキャッシュのサイズを構成します。

スクリプトのサイズは65,535バイトに制限されています。script.max_size_in_bytesの値を設定して、そのソフトリミットを増やします。スクリプトが非常に大きい場合は、ネイティブスクリプトエンジンの使用を検討してください。

検索速度の向上

スクリプトは非常に便利ですが、Elasticsearchのインデックス構造や関連する最適化を使用できません。この関係は、時には検索速度の低下を引き起こすことがあります。

インデックスデータを変換するためにスクリプトを頻繁に使用する場合、代わりにデータを取り込む際に変換することで検索を速くすることができます。ただし、それはしばしばインデックス速度の低下を意味します。検索速度を向上させる方法を示す実用的な例を見てみましょう。

検索を実行する際、2つの値の合計で結果をソートすることは一般的です。たとえば、テストスコアデータを含むインデックスmy_test_scoresを考えてみましょう。このインデックスには、long型の2つのフィールドが含まれています:

  • math_score
  • verbal_score

これらの値を合計するスクリプトを使用してクエリを実行できます。このアプローチには問題はありませんが、スクリプトの評価がリクエストの一部として行われるため、クエリは遅くなります。次のリクエストは、grad_year2099に等しいドキュメントを返し、スクリプトの評価によって結果をソートします。

Python

  1. resp = client.search(
  2. index="my_test_scores",
  3. query={
  4. "term": {
  5. "grad_year": "2099"
  6. }
  7. },
  8. sort=[
  9. {
  10. "_script": {
  11. "type": "number",
  12. "script": {
  13. "source": "doc['math_score'].value + doc['verbal_score'].value"
  14. },
  15. "order": "desc"
  16. }
  17. }
  18. ],
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my_test_scores',
  3. body: {
  4. query: {
  5. term: {
  6. grad_year: '2099'
  7. }
  8. },
  9. sort: [
  10. {
  11. _script: {
  12. type: 'number',
  13. script: {
  14. source: "doc['math_score'].value + doc['verbal_score'].value"
  15. },
  16. order: 'desc'
  17. }
  18. }
  19. ]
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. index: "my_test_scores",
  3. query: {
  4. term: {
  5. grad_year: "2099",
  6. },
  7. },
  8. sort: [
  9. {
  10. _script: {
  11. type: "number",
  12. script: {
  13. source: "doc['math_score'].value + doc['verbal_score'].value",
  14. },
  15. order: "desc",
  16. },
  17. },
  18. ],
  19. });
  20. console.log(response);

コンソール

  1. GET /my_test_scores/_search
  2. {
  3. "query": {
  4. "term": {
  5. "grad_year": "2099"
  6. }
  7. },
  8. "sort": [
  9. {
  10. "_script": {
  11. "type": "number",
  12. "script": {
  13. "source": "doc['math_score'].value + doc['verbal_score'].value"
  14. },
  15. "order": "desc"
  16. }
  17. }
  18. ]
  19. }

小さなインデックスを検索している場合、検索クエリの一部としてスクリプトを含めることは良い解決策です。検索を速くしたい場合は、この計算を取り込み時に実行し、合計をフィールドにインデックスすることができます。

まず、total_scoreという名前の新しいフィールドをインデックスに追加し、math_scoreおよびverbal_scoreフィールドの値の合計を含めます。

Python

  1. resp = client.indices.put_mapping(
  2. index="my_test_scores",
  3. properties={
  4. "total_score": {
  5. "type": "long"
  6. }
  7. },
  8. )
  9. print(resp)

Ruby

  1. response = client.indices.put_mapping(
  2. index: 'my_test_scores',
  3. body: {
  4. properties: {
  5. total_score: {
  6. type: 'long'
  7. }
  8. }
  9. }
  10. )
  11. puts response

Js

  1. const response = await client.indices.putMapping({
  2. index: "my_test_scores",
  3. properties: {
  4. total_score: {
  5. type: "long",
  6. },
  7. },
  8. });
  9. console.log(response);

コンソール

  1. PUT /my_test_scores/_mapping
  2. {
  3. "properties": {
  4. "total_score": {
  5. "type": "long"
  6. }
  7. }
  8. }

次に、インジェストパイプラインを使用して、math_scoreverbal_scoreの合計を計算し、total_scoreフィールドにインデックスします。

Python

  1. resp = client.ingest.put_pipeline(
  2. id="my_test_scores_pipeline",
  3. description="Calculates the total test score",
  4. processors=[
  5. {
  6. "script": {
  7. "source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
  8. }
  9. }
  10. ],
  11. )
  12. print(resp)

Ruby

  1. response = client.ingest.put_pipeline(
  2. id: 'my_test_scores_pipeline',
  3. body: {
  4. description: 'Calculates the total test score',
  5. processors: [
  6. {
  7. script: {
  8. source: 'ctx.total_score = (ctx.math_score + ctx.verbal_score)'
  9. }
  10. }
  11. ]
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.ingest.putPipeline({
  2. id: "my_test_scores_pipeline",
  3. description: "Calculates the total test score",
  4. processors: [
  5. {
  6. script: {
  7. source: "ctx.total_score = (ctx.math_score + ctx.verbal_score)",
  8. },
  9. },
  10. ],
  11. });
  12. console.log(response);

コンソール

  1. PUT _ingest/pipeline/my_test_scores_pipeline
  2. {
  3. "description": "Calculates the total test score",
  4. "processors": [
  5. {
  6. "script": {
  7. "source": "ctx.total_score = (ctx.math_score + ctx.verbal_score)"
  8. }
  9. }
  10. ]
  11. }

既存のデータを更新するには、このパイプラインを使用して、my_test_scoresから新しいインデックスmy_test_scores_2にドキュメントを再インデックスします。

Python

  1. resp = client.reindex(
  2. source={
  3. "index": "my_test_scores"
  4. },
  5. dest={
  6. "index": "my_test_scores_2",
  7. "pipeline": "my_test_scores_pipeline"
  8. },
  9. )
  10. print(resp)

Ruby

  1. response = client.reindex(
  2. body: {
  3. source: {
  4. index: 'my_test_scores'
  5. },
  6. dest: {
  7. index: 'my_test_scores_2',
  8. pipeline: 'my_test_scores_pipeline'
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.reindex({
  2. source: {
  3. index: "my_test_scores",
  4. },
  5. dest: {
  6. index: "my_test_scores_2",
  7. pipeline: "my_test_scores_pipeline",
  8. },
  9. });
  10. console.log(response);

コンソール

  1. POST /_reindex
  2. {
  3. "source": {
  4. "index": "my_test_scores"
  5. },
  6. "dest": {
  7. "index": "my_test_scores_2",
  8. "pipeline": "my_test_scores_pipeline"
  9. }
  10. }

パイプラインを使用して、my_test_scores_2に新しいドキュメントをインデックスし続けます。

Python

  1. resp = client.index(
  2. index="my_test_scores_2",
  3. pipeline="my_test_scores_pipeline",
  4. document={
  5. "student": "kimchy",
  6. "grad_year": "2099",
  7. "math_score": 1200,
  8. "verbal_score": 800
  9. },
  10. )
  11. print(resp)

Ruby

  1. response = client.index(
  2. index: 'my_test_scores_2',
  3. pipeline: 'my_test_scores_pipeline',
  4. body: {
  5. student: 'kimchy',
  6. grad_year: '2099',
  7. math_score: 1200,
  8. verbal_score: 800
  9. }
  10. )
  11. puts response

Js

  1. const response = await client.index({
  2. index: "my_test_scores_2",
  3. pipeline: "my_test_scores_pipeline",
  4. document: {
  5. student: "kimchy",
  6. grad_year: "2099",
  7. math_score: 1200,
  8. verbal_score: 800,
  9. },
  10. });
  11. console.log(response);

コンソール

  1. POST /my_test_scores_2/_doc/?pipeline=my_test_scores_pipeline
  2. {
  3. "student": "kimchy",
  4. "grad_year": "2099",
  5. "math_score": 1200,
  6. "verbal_score": 800
  7. }

これらの変更はインデックスプロセスを遅くしますが、検索を速くすることができます。スクリプトを使用する代わりに、my_test_scores_2で行われた検索をtotal_scoreフィールドを使用してソートできます。応答はほぼリアルタイムです!このプロセスは取り込み時間を遅くしますが、検索時のクエリを大幅に増加させます。

Python

  1. resp = client.search(
  2. index="my_test_scores_2",
  3. query={
  4. "term": {
  5. "grad_year": "2099"
  6. }
  7. },
  8. sort=[
  9. {
  10. "total_score": {
  11. "order": "desc"
  12. }
  13. }
  14. ],
  15. )
  16. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my_test_scores_2',
  3. body: {
  4. query: {
  5. term: {
  6. grad_year: '2099'
  7. }
  8. },
  9. sort: [
  10. {
  11. total_score: {
  12. order: 'desc'
  13. }
  14. }
  15. ]
  16. }
  17. )
  18. puts response

Js

  1. const response = await client.search({
  2. index: "my_test_scores_2",
  3. query: {
  4. term: {
  5. grad_year: "2099",
  6. },
  7. },
  8. sort: [
  9. {
  10. total_score: {
  11. order: "desc",
  12. },
  13. },
  14. ],
  15. });
  16. console.log(response);

コンソール

  1. GET /my_test_scores_2/_search
  2. {
  3. "query": {
  4. "term": {
  5. "grad_year": "2099"
  6. }
  7. },
  8. "sort": [
  9. {
  10. "total_score": {
  11. "order": "desc"
  12. }
  13. }
  14. ]
  15. }