0

適切な方法と思われるため、以前に MySQL 自体でこれを実行しましたが、いくつかのビジネス ロジックの計算を実行し、結果のリストにグループを適用する必要があります。パフォーマンスを犠牲にすることなく Java でこれを実行するための提案 (ラムダジを見て、プロキシを多用したために速度が低下したようですが、試していません)。

List<Item>プロパティとして名前、値、unixtimestamp を含み、データベースによって返されます。各レコードは 5 分間隔です。

つまり、12 レコードごとに 1 つのレコードにグループ化し、各グループに最小、最大、平均、最後を適用する必要があります。

任意の提案をいただければ幸いです。

[更新] 以下を機能させますが、インデックス付きマップ値の各リスト要素の集計はまだ行っていません。ご覧のとおり、リストのマップを作成しました。キーは、要求された整数表現のサンプル時間です (ここで要求されたサンプルは 30 です)。

private List<Item> performConsolidation(List<Item> items) {
        ListMultimap<Integer, Item> groupByTimestamp = ArrayListMultimap.create();
        List<Item> consolidatedItems = new ArrayList<>();
        for (Item item : items) {
            groupByTimestamp.put((int)floor(((Double.valueOf(item.getItem()[2])) / 1000) / (60 * 30)), item);
        }
        return consolidatedItems;
    }
4

3 に答える 3

1

ここに1つの提案があります:

public Map<Long,List<Item>> group_items(List<Item> items,long sample_period) {
  Map<Long,List<Item>> grouped_result = new HashMap<Long,List<Item>>();
  long group_key;

  for (Item item: items) {
    group_key = item.timestamp / sample_period;
    if (grouped_result.containsKey(group_key)) {  
      grouped_result.get(group_key).add(item);
    }
    else {
      grouped_result.put(group_key, new ArrayList<Item>());
      grouped_result.get(group_key).add(item);
    }
  }
  return grouped_result;
}

sample_period は、グループ化する秒数です: 3600 = 時間、900 = 15 分

もちろん、マップ内のキーは非常に大きな数になる可能性があります (サンプル期間によって異なります) が、このグループ化はグループの内部時間順序を保持します。つまり、下位のキーは時間順序で最初に来るキーです。元のリストのデータが時間順に並べられていると仮定すると、もちろん最初のキーの値を取得し、それをキーから差し引くことができます。このようにして、キー 0、1 などを取得します。その場合、for ループを開始する前に次のものが必要です。

int 減算 = items.get(0).timestamp / sample_period; // 両方の数値が ints/longs であるため、整数除算があることに注意してください

次に、for ループ内で次のようにします。

group_key = items.timestamp / sample_period - 減算;

これらの行に沿った何かが機能します。つまり、説明したようにデータセットをグループ化します。次に、結果のリストに min max avg などを適用できます。しかし、これらの関数はもちろん個々のグループ リストを繰り返し処理する必要があるため、これらの計算をこのソリューションに組み込み、Aggregates が avg、min、max、次に、グループ内のアイテムのリスト? 性能に関しては許容範囲だと思います。これは単純な O(N) ソリューションです。編集:

最小値、最大値、平均値も計算する、より完全なソリューション/提案を追加したいだけです。

public class Aggregate {
  public double avg;
  public double min;
  public double max;

  public List<Item> items = new ArrayList<Item>();

  public Aggregate(Item item) {
    min = item.value;
    max = item.value;
    avg = item.value;
    items.add(item);
  }

  public void addItem(Item item) {
    items.add(item);
    if (item.value < this.min) {
      this.min = item.value;
    }
    else if (item.value > this.max) {
      this.max = item.value;
    }
    this.avg = (this.avg * (this.items.size() - 1) + item.value) / this.items.size(); 
  }
}

public Map<Long,Aggregate> group_items(List<Item> items,long sample_period) {

  Map<Long,Aggregate> grouped_result = new HashMap<Long,Aggregate>();
  long group_key;

  long subtract = items.get(0).timestamp / sample_period;
  for (Item item: items) {
    group_key = items.timestamp / sample_period - subtract;
    if (grouped_result.containsKey(group_key)) {  
      grouped_result.get(group_key).addItem(item);
    }
    else {
      grouped_result.put(group_key, new Aggregate(item));
    }
  }
  return grouped_result;
}

それは大まかな解決策です。集計などにさらにいくつかのプロパティを追加したい場合があります。

于 2014-07-09T12:09:06.007 に答える
0

最小/最大/などの計算は別として、あなたのperformConsolidation方法は を使用できるように見えることに注意してくださいMultimaps.indexFunction<Item, Integer>必要な値を計算するアイテムと a を渡すだけです。

return (int) floor(((Double.valueOf(item.getItem()[2])) / 1000) / (60 * 30));

これで大量のコードが節約されるわけではありませんが、何が起こっているのかを一目で簡単に確認できるようになる可能性があります: index(items, timeBucketer).

于 2014-07-16T14:38:15.173 に答える