복붙노트

[MONGODB] MongoDB를의 통합 프레임 워크 이동 평균?

MONGODB

MongoDB를의 통합 프레임 워크 이동 평균?

당신은 당신이 이동 평균 계산합니다 방법 (예를 들어) (매일) 온도 기상 데이터 50 년, 그 시간 동안, 3 개월 간격을 사용하여이 있다면? 당신은 하나 개의 쿼리로 그렇게 할 수 또는 여러 개의 쿼리를해야 할 것?

Example Data

01/01/2014 = 40 degrees
12/31/2013 = 38 degrees
12/30/2013 = 29 degrees
12/29/2013 = 31 degrees
12/28/2013 = 34 degrees
12/27/2013 = 36 degrees
12/26/2013 = 38 degrees
.....

해결법

  1. ==============================

    1.AGG 프레임 워크는 현재 $지도를 가지고 있으며, $ 감소와 $는 배열 처리가 훨씬 더 straightfoward되도록 내장 범위. 다음은 몇 가지 조건에 의해 필터 할 경우 데이터 집합에 대한 이동 평균 계산의 예입니다. 기본 설정은 각 문서는 필터링이 기준 값과, 예를 들어 포함되고

    AGG 프레임 워크는 현재 $지도를 가지고 있으며, $ 감소와 $는 배열 처리가 훨씬 더 straightfoward되도록 내장 범위. 다음은 몇 가지 조건에 의해 필터 할 경우 데이터 집합에 대한 이동 평균 계산의 예입니다. 기본 설정은 각 문서는 필터링이 기준 값과, 예를 들어 포함되고

    {sym: "A", d: ISODate("2018-01-01"), val: 10}
    {sym: "A", d: ISODate("2018-01-02"), val: 30}
    

    여기있어:

    // This controls the number of observations in the moving average:
    days = 4;
    
    c=db.foo.aggregate([
    
    // Filter down to what you want.  This can be anything or nothing at all.
    {$match: {"sym": "S1"}}
    
    // Ensure dates are going earliest to latest:
    ,{$sort: {d:1}}
    
    // Turn docs into a single doc with a big vector of observations, e.g.
    //     {sym: "A", d: d1, val: 10}
    //     {sym: "A", d: d2, val: 11}
    //     {sym: "A", d: d3, val: 13}
    // becomes
    //     {_id: "A", prx: [ {v:10,d:d1}, {v:11,d:d2},  {v:13,d:d3} ] }
    //
    // This will set us up to take advantage of array processing functions!
    ,{$group: {_id: "$sym", prx: {$push: {v:"$val",d:"$date"}} }}
    
    // Nice additional info.  Note use of dot notation on array to get
    // just scalar date at elem 0, not the object {v:val,d:date}:
    ,{$addFields: {numDays: days, startDate: {$arrayElemAt: [ "$prx.d", 0 ]}} }
    
    // The Juice!  Assume we have a variable "days" which is the desired number
    // of days of moving average.
    // The complex expression below does this in python pseudocode:
    //
    // for z in range(0, size of value vector - # of days in moving avg):
    //    seg = vector[n:n+days]
    //    values = seg.v
    //    dates = seg.d
    //    for v in seg:
    //        tot += v
    //    avg = tot/len(seg)
    // 
    // Note that it is possible to overrun the segment at the end of the "walk"
    // along the vector, i.e. not enough date-values.  So we only run the
    // vector to (len(vector) - (days-1).
    // Also, for extra info, we also add the number of days *actually* used in the
    // calculation AND the as-of date which is the tail date of the segment!
    //
    // Again we take advantage of dot notation to turn the vector of
    // object {v:val, d:date} into two vectors of simple scalars [v1,v2,...]
    // and [d1,d2,...] with $prx.v and $prx.d
    //
    ,{$addFields: {"prx": {$map: {
        input: {$range:[0,{$subtract:[{$size:"$prx"}, (days-1)]}]} ,
        as: "z",
        in: {
           avg: {$avg: {$slice: [ "$prx.v", "$$z", days ] } },
           d: {$arrayElemAt: [ "$prx.d", {$add: ["$$z", (days-1)] } ]}
            }
            }}
        }}
    
                ]);
    

    이것은 다음과 같은 출력을 생성 할 수 있습니다 :

    {
        "_id" : "S1",
        "prx" : [
            {
                "avg" : 11.738793632512115,
                "d" : ISODate("2018-09-05T16:10:30.259Z")
            },
            {
                "avg" : 12.420766702631376,
                "d" : ISODate("2018-09-06T16:10:30.259Z")
            },
            ...
    
        ],
        "numDays" : 4,
        "startDate" : ISODate("2018-09-02T16:10:30.259Z")
    }
    
  2. ==============================

    2.내가 MongoDB의에서이 작업을 수행하는 경향이 방법은 예를 들어, 매일의 가치에 대한 문서에서 지난 90 일 실행 합계를 유지하다

    내가 MongoDB의에서이 작업을 수행하는 경향이 방법은 예를 들어, 매일의 가치에 대한 문서에서 지난 90 일 실행 합계를 유지하다

    {"day": 1, "tempMax": 40, "tempMaxSum90": 2232}
    {"day": 2, "tempMax": 38, "tempMaxSum90": 2230}
    {"day": 3, "tempMax": 36, "tempMaxSum90": 2231}
    {"day": 4, "tempMax": 37, "tempMaxSum90": 2233}
    

    새로운 데이터 포인트 대신 읽고 효율적이 간단한 쿼리, 하나 또한이 (사이비 코드)와 같은 하나의 뺄셈으로 다음 합계를 계산할 수 (90 개) 값을 합산의 컬렉션에 추가해야 할 때마다 :

    tempMaxSum90(day) = tempMaxSum90(day-1) + tempMax(day) - tempMax(day-90)
    

    매일 다음 인에 대한 90 일 이동 평균은 90 일의 합은 90로 나눈 값.

    당신은 또한 다른 이상 이동 평균을 제공하고 싶었 시간 규모 (예 : 일주, 삼십일 90 일, 1 년) 단순히 때마다하는 대신 하나의 합의 각 문서와 금액의 배열, 하나의 합을 유지할 수 -scale이 필요합니다.

    그러나이 접근법은 새로운 데이터를 비교적 느리게 수집되는 빠른 검색이 바람직한 시나리오 차트 가장 시계열에 적합한 추가 저장 용량과 새로운 데이터를 삽입하기위한 추가 처리를 요한다.

  3. ==============================

    3.나는 적어도 몇 가지 심각한 체조하지 않고이 작업을 수행 할 수 있으며, 통합 프레임 워크는 현재 버전 (2.6)에 여러 날짜에 대해이 작업을 수행 할 수 있다고 생각하거나하지 않습니다. 그 이유는 어떻게 든 관련 정보의 이전 3 개월의 가치를 포함하는 각 일에 대한 문서를 작성하는 것이 필요하다, 그래서 집계 파이프 라인은 한 번에 하나 개의 문서 만 하나의 문서를 처리하는 것입니다. 이것은 이전의 단계는 $ 그룹에 사용 할 수있는 몇 가지 구별 키와 매일의 기록 (90 개) 사본에 대한 생산 것을 의미 평균을 계산합니다 달러 (A $) 조별로 될 것입니다.

    나는 적어도 몇 가지 심각한 체조하지 않고이 작업을 수행 할 수 있으며, 통합 프레임 워크는 현재 버전 (2.6)에 여러 날짜에 대해이 작업을 수행 할 수 있다고 생각하거나하지 않습니다. 그 이유는 어떻게 든 관련 정보의 이전 3 개월의 가치를 포함하는 각 일에 대한 문서를 작성하는 것이 필요하다, 그래서 집계 파이프 라인은 한 번에 하나 개의 문서 만 하나의 문서를 처리하는 것입니다. 이것은 이전의 단계는 $ 그룹에 사용 할 수있는 몇 가지 구별 키와 매일의 기록 (90 개) 사본에 대한 생산 것을 의미 평균을 계산합니다 달러 (A $) 조별로 될 것입니다.

    그래서 하나의 집계에 한 번에 두 개 이상의 날짜에 대해이 작업을 수행 할 수있는 방법을 볼 수 없습니다. 나는 그래서 실제 아니다 복잡하더라도, 잘못하고 / 편집해야 할 누군가가 그것을 할 수있는 방법을 발견하면이 답변을 제거 드리겠습니다. PostgreSQL의 파티션 유형의 기능은 여기에 일을 할 것입니다; 어쩌면 그 기능은 언젠가 추가됩니다.

  4. ==============================

    4.나는 내 자신의 질문에 대한 답이있을 수 있습니다 생각합니다. 그것을 할 것입니다 줄지도. 먼저 사용되는 발광 다음 각 배열을 평균 할 줄 사용이로 평균되어야한다 그것의 이웃에 각 문서를지도로 ... 그리고 그것의 ID가 새로운 날짜 간격이 될 것이기 때문에 평균의 새로운 배열은 이동 평균 플롯 초과 근무해야한다 당신은에 대한 관심

    나는 내 자신의 질문에 대한 답이있을 수 있습니다 생각합니다. 그것을 할 것입니다 줄지도. 먼저 사용되는 발광 다음 각 배열을 평균 할 줄 사용이로 평균되어야한다 그것의 이웃에 각 문서를지도로 ... 그리고 그것의 ID가 새로운 날짜 간격이 될 것이기 때문에 평균의 새로운 배열은 이동 평균 플롯 초과 근무해야한다 당신은에 대한 관심

    나는 더 나은지도-감소 이해하는 데 필요한 것 같아요 ...

    :)

    예를 들어 ... 우리가 메모리에하고 싶었던 경우 (나중에 우리가 컬렉션을 만들 수 있습니다)

    GIST https://gist.github.com/mrgcohen/3f67c597a397132c46f7

    표정의 권리를합니까?

  5. ==============================

    5.허용 대답은 나에게 도움이 있지만, 내가 그것을 어떻게 작동하는지 이해하는 렸어요 그리고 내가 밖으로 도움이 다른 사람에게 내 방법을 설명 거라고 생각 때문에. 특히 당신의 상황에 내 대답은 도움이 될 것입니다 생각

    허용 대답은 나에게 도움이 있지만, 내가 그것을 어떻게 작동하는지 이해하는 렸어요 그리고 내가 밖으로 도움이 다른 사람에게 내 방법을 설명 거라고 생각 때문에. 특히 당신의 상황에 내 대답은 도움이 될 것입니다 생각

    이상적으로 작은 데이터 세트에이 작품

    첫번째 그룹 하루 데이터는 각각의 하루 어레이의 모든 추가 일 :

    {
      "$sort": {
        "Date": -1
      }
    },
    {
      "$group": {
        "_id": {
          "Day": "$Date",
          "Temperature": "$Temperature"
        },
        "Previous Values": {
          "$push": {
            "Date": "$Date",
            "Temperature": "$Temperature"
          }
        }
      }
    

    이 모습은 다음과 같이 (올바르게 정렬됩니다)하는 기록 당신을 떠날 것이다 :

    {"_id.Day": "2017-02-01", 
    "Temperature": 40, 
    "Previous Values": [
        {"Day": "2017-03-01", "Temperature": 20},
        {"Day": "2017-02-11", "Temperature": 22},
        {"Day": "2017-01-18", "Temperature": 03},
        ...
        ]},
    

    이제 매일이 추가 모든 일을 가지고, 우리는 이동 평균이 찾고 뒤로 한,이 _id.Day 필드보다 최신 이전 값 배열에서 항목을 제거해야합니다 :

    {
      "$project": {
        "_id": 0,
        "Date": "$_id.Date",
        "Temperature": "$_id.Temperature",
        "Previous Values": 1
      }
    },
    {
      "$project": {
        "_id": 0,
        "Date": 1,
        "Temperature": 1,
        "Previous Values": {
          "$filter": {
            "input": "$Previous Values",
            "as": "pv",
            "cond": {
              "$lte": ["$$pv.Date", "$Date"]
            }
          }
        }
      }
    },
    

    이전 값의 배열의 각 항목은보다 작거나 각 레코드의 날짜에 동일 날짜를 포함합니다 :

    {"Day": "2017-02-01", 
    "Temperature": 40, 
    "Previous Values": [
        {"Day": "2017-01-31", "Temperature": 33},
        {"Day": "2017-01-30", "Temperature": 36},
        {"Day": "2017-01-29", "Temperature": 33},
        {"Day": "2017-01-28", "Temperature": 32},
        ...
        ]}
    

    데이터가 하루이기 때문에 우리는 배열의 첫 번째 (7 개) 기록을 거라고 주 동안 이제 우리는, 우리의 평균 창 크기를 선택할 수 있습니다; 월에, 30; 또는 3 월 90 일 :

    {
      "$project": {
        "_id": 0,
        "Date": 1,
        "Temperature": 1,
        "Previous Values": {
          "$slice": ["$Previous Values", 0, 90]
        }
      }
    },
    

    이전의 온도를 평균하기 위해 우리는 날짜 필드에서 다음 그룹을 이전 값의 배열을 긴장. 언 와인드 작업이 수행 :

    {"Day": "2017-02-01", 
    "Temperature": 40, 
    "Previous Values": {
            "Day": "2017-01-31", 
            "Temperature": 33}
    },
    
    {"Day": "2017-02-01", 
    "Temperature": 40, 
    "Previous Values": {
            "Day": "2017-01-30", 
            "Temperature": 36}
    },
    
    {"Day": "2017-02-01", 
    "Temperature": 40, 
    "Previous Values": {
            "Day": "2017-01-29", 
            "Temperature": 33}
    },
    ...
    

    오늘 필드가 동일하다고 볼 수 있지만, 우리는 지금 이전 값 배열에서 이전 날짜의 각각에 대한 문서가 있습니다. 이제 우리는 하루에 그룹 다시 후 평균 이전 Values.Temperature은 이동 평균을 얻을 수 있습니다 :

    {"$group": {
        "_id": {
          "Day": "$Date",
          "Temperature": "$Temperature"
        },
        "3 Month Moving Average": {
          "$avg": "$Previous Values.Temperature"
        }
      }
    }
    

    즉입니다! 나는 모든 레코드에 모든 레코드에 합류하는 것은 적합하지 않습니다 것을 알고 있지만,이 작은 데이터 세트에서 잘 작동합니다

  6. from https://stackoverflow.com/questions/25151042/moving-averages-with-mongodbs-aggregation-framework by cc-by-sa and MIT license