Spec-Zone.ru › Elasticsearch 8
›Руководство по Elasticsearch [8.17] ›Агрегации ›Агрегации поэтапного типа

Агрегация скользящей функции

Для упорядоченной последовательности данных агрегация скользящей функции сдвигает окно по данным и позволяет пользователю указать пользовательский скрипт, который выполняется для каждого окна данных. Для удобства предусмотрено несколько общих функций, таких как min/max, скользящие средние и т.д.

Синтаксис

Агрегация moving_fn выглядит следующим образом:

{
  "moving_fn": {
    "buckets_path": "the_sum",
    "window": 10,
    "script": "MovingFunctions.min(values)"
  }
}

Таблица 66. moving_fn Параметры

Имя параметра Описание Обязательно Значение по умолчанию

buckets_path

Путь к метрике, представляющей интерес (см. buckets_path Синтаксис для получения подробной информации)

Обязательно

window

Размер окна, которое "сдвигается" по гистограмме.

Обязательно

script

Скрипт, который должен выполняться для каждого окна данных

Обязательно

gap_policy

Политика, которая применяется при обнаружении разрывов в данных. См. Обработка разрывов в данных.

Необязательно

skip

shift

Сдвиг положения окна.

Необязательно

0

Агрегации moving_fn должны быть вложены в histogram или date_histogram агрегацию. Их можно вкладывать как и другие метрические агрегации:

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movfn": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.unweightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movfn: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.unweightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movfn: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.unweightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {                  
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }   
        },
        "the_movfn": {
          "moving_fn": {
            "buckets_path": "the_sum",  
            "window": 10,
            "script": "MovingFunctions.unweightedAvg(values)"
          }
        }
      }
    }
  }
}

Создается date_histogram с именем "my_date_histo" по полю "timestamp" с интервалами в один месяц

Используется метрика sum для вычисления суммы поля. Это может быть любая числовая метрика (сумма, минимум, максимум и т.д.)

В заключение, задаётся агрегация moving_fn, которая использует метрику "the_sum" в качестве входных данных.

Скользящие средние строятся путём сначала указания histogram или date_histogram по полю. Затем вы можете необязательно добавить числовые метрики, такие как sum, внутри этой гистограммы. Наконец, агрегация moving_fn вкладывается внутрь гистограммы. Параметр buckets_path используется для указания одной из метрик-сестёр внутри гистограммы (см. buckets_path Синтаксис для описания синтаксиса для buckets_path).

Пример ответа от вышеуказанной агрегации может быть таким:

{
   "took": 11,
   "timed_out": false,
   "_shards": ...,
   "hits": ...,
   "aggregations": {
      "my_date_histo": {
         "buckets": [
             {
                 "key_as_string": "2015/01/01 00:00:00",
                 "key": 1420070400000,
                 "doc_count": 3,
                 "the_sum": {
                    "value": 550.0
                 },
                 "the_movfn": {
                    "value": null
                 }
             },
             {
                 "key_as_string": "2015/02/01 00:00:00",
                 "key": 1422748800000,
                 "doc_count": 2,
                 "the_sum": {
                    "value": 60.0
                 },
                 "the_movfn": {
                    "value": 550.0
                 }
             },
             {
                 "key_as_string": "2015/03/01 00:00:00",
                 "key": 1425168000000,
                 "doc_count": 2,
                 "the_sum": {
                    "value": 375.0
                 },
                 "the_movfn": {
                    "value": 305.0
                 }
             }
         ]
      }
   }
}

Настройка пользовательских скриптов

Агрегация функции Moving Function позволяет пользователю указать любой произвольный скрипт для определения пользовательской логики. Скрипт вызывается каждый раз, когда собирается новый набор данных. Эти значения передаются скрипту в переменной values. Скрипт должен выполнить какое-либо вычисление и вывести одно double в качестве результата. Вывод null запрещён, хотя NaN и +/- Inf разрешены.

Например, этот скрипт просто вернёт первое значение из окна или NaN, если доступных значений нет:

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "return values.length > 0 ? values[0] : Double.NaN"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'return values.length > 0 ? values[0] : Double.NaN'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "return values.length > 0 ? values[0] : Double.NaN",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "return values.length > 0 ? values[0] : Double.NaN"
          }
        }
      }
    }
  }
}

Параметр сдвига

По умолчанию (с shift = 0), окно, предлагаемое для вычисления, содержит последние n значения, за исключением текущего значения. Увеличение shift на 1 сдвигает начальную позицию окна на 1 вправо.

  • Чтобы включить текущее значение в окно, используйте shift = 1.
  • Для центрирования (n / 2 значений до и после текущего значения), используйте shift = window / 2.
  • Для выравнивания по правому краю (n значений после текущего значения), используйте shift = window.

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

Встроенные функции

Для удобства, ряд функций был встроен и доступен в контексте скрипта moving_fn:

  • max()
  • min()
  • sum()
  • stdDev()
  • unweightedAvg()
  • linearWeightedAvg()
  • ewma()
  • holt()
  • holtWinters()

Функции доступны из пространства имён MovingFunctions. Например, MovingFunctions.max()

Функция max

Эта функция принимает набор значений типа double и возвращает максимальное значение в этом диапазоне. Значения null и NaN игнорируются; максимальное значение вычисляется только для действительных значений. Если диапазон пуст или все значения являются null/NaN, в качестве результата возвращается NaN.

Таблица 67. Параметры функции max(double[] values)

Имя параметра Описание

values

Диапазон значений для поиска максимального значения

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_max": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.max(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_max: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.max(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_max: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.max(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_max": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.max(values)"
          }
        }
      }
    }
  }
}

Функция min

Эта функция принимает набор значений типа double и возвращает минимальное значение в этом диапазоне. Значения null и NaN игнорируются; минимальное значение вычисляется только для действительных значений. Если диапазон пуст или все значения являются null/NaN, в качестве результата возвращается NaN.

Таблица 68. Параметры функции min(double[] values)

Имя параметра Описание

values

Диапазон значений для поиска минимального значения

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_min": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.min(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_min: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.min(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_min: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.min(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_min": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.min(values)"
          }
        }
      }
    }
  }
}

Функция sum

Эта функция принимает набор значений типа double и возвращает сумму значений в этом диапазоне. Значения null и NaN игнорируются; сумма вычисляется только для действительных значений. Если диапазон пуст или все значения являются null/NaN, в качестве результата возвращается 0.0.

Таблица 69. Параметры функции sum(double[] values)

Имя параметра Описание

values

Диапазон значений для вычисления суммы

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_sum": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.sum(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_sum: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.sum(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_sum: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.sum(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_sum": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.sum(values)"
          }
        }
      }
    }
  }
}

Функция stdDev

Эта функция принимает набор значений типа double и среднее значение, а затем возвращает стандартное отклонение значений в этом окне. Значения null и NaN игнорируются; сумма вычисляется только для действительных значений. Если окно пустое или все значения являются null/NaN, в качестве результата возвращается 0.0.

Таблица 70. Параметры функции stdDev(double[] values)

Имя параметра Описание

values

Окно значений, для которых нужно вычислить стандартное отклонение

avg

Среднее значение окна

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_sum": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_sum: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_sum: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script:
              "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_sum": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))"
          }
        }
      }
    }
  }
}

Параметр avg должен быть предоставлен функции стандартного отклонения, потому что различные типы средних значений могут быть вычислены в окне (простые, взвешенные по линейному закону и т.д.). Различные скользящие средние, описанные ниже, могут быть использованы для вычисления среднего значения для функции стандартного отклонения.

Функция unweightedAvg

Функция unweightedAvg вычисляет сумму всех значений в окне, а затем делит на размер окна. Это эффективно является простым средним арифметическим значением окна. Простое скользящее среднее не выполняет никакого временного взвешивания, что означает, что значения от simple скользящего среднего имеют тенденцию «отставать» от реальных данных.

Значения null и NaN игнорируются; среднее значение вычисляется только для действительных значений. Если окно пустое или все значения являются null/NaN, возвращается NaN. Это означает, что количество, используемое в расчете среднего значения, равно количеству значений, не являющихся null, не являющихся NaN.

Таблица 71. Параметры функции unweightedAvg(double[] values)

Имя параметра Описание

values

Окно значений, для которых нужно найти сумму

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.unweightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.unweightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.unweightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.unweightedAvg(values)"
          }
        }
      }
    }
  }
}

Функция linearWeightedAvg

Функция linearWeightedAvg назначает линейное взвешивание точкам в ряду, так что "более старые" точки данных (например, те, что в начале окна) вносят линейно меньший вклад в общее среднее значение. Линейное взвешивание помогает уменьшить «отставание» от среднего значения данных, так как более старые точки имеют меньшее влияние.

Если окно пустое или все значения являются null/NaN, возвращается NaN.

Таблица 72. Параметры функции linearWeightedAvg(double[] values)

Имя параметра Описание

values

Окно значений, для которых нужно найти сумму

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.linearWeightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.linearWeightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.linearWeightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.linearWeightedAvg(values)"
          }
        }
      }
    }
  }
}

Функция ewma

Функция ewma (также известная как "экспоненциально-взвешенное скользящее среднее") похожа на функцию linearMovAvg, за исключением того, что более старые точки данных становятся экспоненциально менее значимыми, а не линейно. Скорость, с которой важность убывает, можно контролировать с помощью параметра alpha. Малые значения приводят к медленному убыванию весов, обеспечивая большую сглаженность и учитывая большую часть окна. Большие значения приводят к быстрому убыванию весов, что уменьшает влияние более старых значений на скользящее среднее. Это способствует более точному отслеживанию данных, но с меньшей сглаженностью.

Значения null и NaN игнорируются; среднее значение вычисляется только для реальных значений. Если окно пустое или все значения являются null/NaN, результат будет NaN. Это означает, что количество, используемое в расчете среднего значения, — это количество ненулевых, не-null, не-NaN значений.

Таблица 73. Параметры функции ewma(double[] values, double alpha)

Имя параметра Описание

values

Окно значений для нахождения суммы

alpha

Экспоненциальное убывание

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.ewma(values, 0.3)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.ewma(values, 0.3)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.ewma(values, 0.3)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.ewma(values, 0.3)"
          }
        }
      }
    }
  }
}

Функция holt

Функция holt (также известная как "двойное экспоненциальное скользящее среднее") включает второй экспоненциальный член, который отслеживает тренд данных. Простое экспоненциальное скользящее среднее не работает хорошо, когда данные имеют подлежащий линейный тренд. Двойная экспоненциальная модель вычисляет два значения: "уровень" и "тенденцию".

Вычисление уровня аналогично ewma и представляет собой экспоненциально взвешенное представление данных. Разница в том, что вместо исходного значения используется ранее сглаженное значение, что позволяет ему оставаться близким к исходному ряду. Вычисление тренда рассматривает разницу между текущим и последним значением (например, наклон или тренд сглаженных данных). Значение тренда также экспоненциально взвешено.

Значения получаются путем умножения компонент уровня и тренда.

Значения null и NaN игнорируются; среднее значение вычисляется только для реальных значений. Если окно пустое или все значения являются null/NaN, результат будет NaN. Это означает, что количество, используемое в расчете среднего значения, — это количество ненулевых, не-null, не-NaN значений.

Таблица 74. Параметры функции holt(double[] values, double alpha)

Имя параметра Описание

values

Окно значений для нахождения суммы

alpha

Значение убывания уровня

beta

Значение убывания тренда

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.holt(values, 0.3, 0.1)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.holt(values, 0.3, 0.1)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.holt(values, 0.3, 0.1)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.holt(values, 0.3, 0.1)"
          }
        }
      }
    }
  }
}

На практике значение alpha ведет себя очень похоже в holtMovAvg как и ewmaMovAvg: небольшие значения производят больше сглаживания и задержки, а большие значения производят более точное отслеживание и меньшую задержку. Значение beta часто трудно оценить. Малые значения подчеркивают долгосрочные тренды (например, постоянный линейный тренд на всем ряде), а большие значения подчеркивают краткосрочные тренды.

Функция holtWinters

Функция holtWinters (также известная как «тройная экспоненциальная») включает третий экспоненциальный член, который отслеживает сезонную составляющую ваших данных. Таким образом, эта агрегация сглаживается по трём компонентам: «уровень», «тенденция» и «сезонность».

Расчёт уровня и тренда идентичен расчёту в holt. Расчёт сезонности рассматривает разницу между текущей точкой и точкой, предшествующей ей на один период.

Для Holt-Winters требуется немного больше ручного управления, чем для других скользящих средних. Вам нужно указать «периодичность» ваших данных: например, если ваши данные имеют циклические тенденции каждые 7 дней, вы бы установили period = 7. Аналогично, если есть месячная тенденция, вы бы установили её в 30. В настоящее время нет возможности определения периодичности, хотя это запланировано для будущих улучшений.

Значения null и NaN игнорируются; среднее значение рассчитывается только по реальным значениям. Если окно пустое или все значения являются null/NaN, NaN возвращается в качестве результата. Это означает, что количество, используемое в расчёте среднего значения, равно количеству не-null, не-NaN значений.

Таблица 75. Параметры функции holtWinters(double[] values, double alpha)

Имя параметра Описание

values

Окно значений для поиска суммы

alpha

Значение затухания уровня

beta

Значение затухания тренда

gamma

Значение затухания сезонности

period

Периодичность данных

multiplicative

Истинно, если вы хотите использовать мультипликативную Holt-Winters, ложно для аддитивной

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "if (values.length > 5*2) {MovingFunctions.holtWinters(values, 0.3, 0.1, 0.1, 5, false)}"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'if (values.length > 5*2) {MovingFunctions.holtWinters(values, 0.3, 0.1, 0.1, 5, false)}'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script:
              "if (values.length > 5*2) {MovingFunctions.holtWinters(values, 0.3, 0.1, 0.1, 5, false)}",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "if (values.length > 5*2) {MovingFunctions.holtWinters(values, 0.3, 0.1, 0.1, 5, false)}"
          }
        }
      }
    }
  }
}

Мультипликативная Holt-Winters работает путём деления каждой точки данных на сезонное значение. Это проблематично, если какие-либо из ваших данных равны нулю или если в данных есть пробелы (поскольку это приводит к делению на ноль). Для решения этой проблемы mult Holt-Winters дополняет все значения очень маленьким значением (1*10-10), чтобы все значения были отличны от нуля. Это влияет на результат, но только незначительно. Если ваши данные не равны нулю или вы предпочитаете видеть NaN при встрече нулевых значений, вы можете отключить это поведение с помощью pad: false

«Холодный старт»

К сожалению, из-за природы Holt-Winters, ему требуется два периода данных для «запуска» алгоритма. Это означает, что ваши данные window всегда должны быть как минимум вдвое больше, чем ваш период. Если это не так, будет выброшено исключение. Это также означает, что Holt-Winters не будет генерировать значение для первых 2 * period блоков; текущий алгоритм не выполняет обратное прогнозирование.

В приведенном выше примере вы заметите оператор if (), проверяющий размер значений. Это проверка, чтобы убедиться, что у нас есть два периода данных (5 * 2, где 5 — период, указанный в функции holtWintersMovAvg), прежде чем вызывать функцию holt-winters.

© 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/search-aggregations-pipeline-movfn-aggregation.html

Spec-Zone.ru

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