web-dev-qa-db-ja.com

10億個の数値の中央値を計算する

10個の数字と100個のコンピューターがある場合、これらの数字の中央値を見つける最良の方法は何ですか?

私が持っている1つの解決策は次のとおりです。

  • セットをコンピューター間で均等に分割します。
  • それらを並べ替えます。
  • 各セットの中央値を見つけます。
  • 中央値でセットを並べ替えます。
  • 最低から最高の中央値まで一度に2つのセットをマージします。

m1 < m2 < m3 ...がある場合、最初にSet1Set2をマージし、結果セットでSet12(マージ済み)の中央値よりも小さいすべての数値を破棄できます。したがって、いつでも同じサイズのセットがあります。ところで、これを並行して行うことはできません。何か案は?

123
anony

ああ、私の脳はちょうどギアに蹴りました、私は今賢明な提案をしています。これがインタビューであった場合はおそらく遅すぎますが、気にしないでください:

マシン1は「制御マシン」と呼ばれ、議論のために、すべてのデータから開始して他の99台のマシンに均等に送信するか、データがマシン間で均等に分散されます。データの1/99を他のそれぞれに送信します。パーティションは同じである必要はなく、近いだけです。

他の各マシンはそのデータをソートし、最初に低い値を見つけるのを好む方法でソートします。したがって、たとえば、クイックソートでは、常にパーティションの下部を最初にソートします[*]。できるだけ早く昇順で制御マシンにデータを書き戻します(非同期IOを使用してソートを続行し、おそらくNagleをオンにして:少し実験してください)。

制御マシンは、データが到着すると99方向のマージを実行しますが、マージしたデータを破棄し、見た値の数のカウントを保持します。中央値は、20億番目と20億プラス1番目の値の平均として計算されます。

これは「群れで最も遅い」問題に悩まされています。アルゴリズムは、中央値よりも小さいすべての値が選別機によって送信されるまで完了できません。そのような値の1つがデータパーセル内で非常に高い可能性があります。したがって、データの初期分割が完了すると、推定実行時間は、データの1/99をソートして制御コンピューターに送り返す時間と、制御がデータの1/2を読み取る時間の組み合わせになります。 「組み合わせ」は、最大値とそれらの時間の合計の間のどこか、おそらく最大値に近いものです。

私の本能は、ネットワーク経由でデータを送信するよりも高速にデータを送信するには(メディアンを選択するだけでなく)、かなり高速なネットワークである必要があるということです。たとえば、データを含むRAMへのアクセスが等しい100個のコアがある場合など、ネットワークが瞬間的であると推定できる場合は、より良い可能性があります。

ネットワークI/Oは制限される可能性が高いため、少なくとも制御マシンに戻ってくるデータについては、いくつかのトリックを使用できます。たとえば、「1,2,3、.. 100」を送信する代わりに、おそらくソーティングマシンは「100値が101未満」を意味するメッセージを送信できます。次に、制御マシンは変更されたマージを実行できます。このマージでは、範囲外のすべての値のうち最小のものを見つけ、すべてのソートマシンにそれが何であるかを伝えます。多くの値がその値よりも「カウント」され、(b)ソートされたデータの送信をそのポイントから再開します。

より一般的には、制御マシンが99個のソーティングマシンでプレイできる、巧妙なチャレンジレスポンス推測ゲームがおそらくあります。

ただし、これにはマシン間の往復が含まれますが、これは私のより単純な最初のバージョンでは回避できます。私は彼らの相対的なパフォーマンスを盲目的に見積もる方法を本当に知りません、そして、トレードオフは複雑であるので、これがこれまでに本当の問題であると仮定して、私が自分で考える何よりもはるかに良い解決策があると思います。

[*]利用可能なスタック許可-最初に実行する部分の選択は、O(N)余分なスペースがない場合に制限されます。しかし、十分な余分なスペースがある場合は、選択してください。十分なスペースがない場合は、最初のいくつかのパーティションで小さな部分を最初に行うことで、少なくともいくつかのコーナーをカットするために必要なものを使用できます。

53
Steve Jessop
sort -g numbers | head -n 500000001 | tail -n 2 | dc -e "1 k ? ? + 2 / p"
51
DrPizza

私はここで反論者になるのは嫌いですが、ソートが必要だとは思わないので、10億/ 100個の数字をソートするアルゴリズムは遅いと思います。 1台のコンピューターでアルゴリズムを考えてみましょう。

1)10億個からランダムに1000個の値を選択し、それらを使用して、数値の分布、特に範囲を把握します。

2)値を並べ替える代わりに、計算した分布に基づいてバケットに割り当てます。バケットの数は、コンピューターがそれらを効率的に処理できるように選択されますが、それ以外の場合は便利な限り大きくする必要があります。バケットの範囲は、各バケットにほぼ同じ数の値が入るようにする必要があります(これはアルゴリズムにとって重要ではありませんが、効率性に役立ちます。100,000バケットが適切な場合があります)。各バケットの値の数に注意してください。これはO(n)プロセスです。

3)中央値があるバケット範囲を見つけます。これは、各バケットの合計数を調べるだけで実行できます。

4)そのバケットの値を調べて、実際の中央値を見つけます。必要に応じて、ここで並べ替えを使用できます。並べ替えるのは10,000個程度であるためです。そのバケットの値の数が多い場合は、ソートするのに十分な数になるまで、このアルゴリズムを再び使用できます。

このアプローチは、コンピューター間で値を分割することにより、簡単に並列化します。各コンピューターは、各バケットの合計をステップ3を実行する「制御」コンピューターに報告します。ステップ4では、各コンピューターは関連するバケットの(ソートされた)値を制御コンピューターに送信します(これらのアルゴリズムの両方を並行して実行することもできますが、しかし、それはおそらく価値がありません)。

バケットの数が十分に大きい場合、ステップ3と4はどちらも簡単なので、合計プロセスはO(n)です。

24
DJClayworth

10億は、実際には現代のコンピューターにとっては退屈な作業です。ここでは、4 GBの4バイト整数の価値について話しています... 4 GB ...これは、一部のスマートフォンのRAMです。

public class Median {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        int[] numbers = new int[1_000_000_000];

        System.out.println("created array after " +  (System.currentTimeMillis() - start) + " ms");

        Random Rand = new Random();
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = Rand.nextInt();
        }

        System.out.println("initialized array after " + (System.currentTimeMillis() - start) + " ms");

        Arrays.sort(numbers);

        System.out.println("sorted array after " + (System.currentTimeMillis() - start) + " ms");

        if (numbers.length % 2 == 1) {
            System.out.println("median = " + numbers[numbers.length / 2 - 1]);
        } else {
            int m1 = numbers[numbers.length / 2 - 1];
            int m2 = numbers[numbers.length / 2];
            double m = ((long) m1 + m2) / 2.0;
            System.out.println("median = " + new DecimalFormat("#.#").format(m));
        }
}

私のマシンでの出力:

created array after 518 ms
initialized array after 10177 ms
sorted array after 102936 ms
median = 19196

したがって、これは単一のコアを使用して2分未満(1:43で0:10が乱数を生成する)で私のマシン上で完了し、完全な並べ替えさえ行います。本当に素晴らしいものはありません。

これは確かに、大きな数字のセットにとって興味深いタスクです。ここで言いたいのは、10億はピーナッツです。したがって、驚くほど単純なタスクで複雑なソリューションを投げ始める前に、よく考えてください;)

11
sfussenegger

中央値および99パーセンタイルなどの順序統計のestimationは、 t-digest または Q-digest

いずれかのアルゴリズムを使用して、各ノードはダイジェストを生成します。これは、ローカルに保存された値の分布を表します。ダイジェストは単一のノードで収集され、マージされ(効果的に分布を合計し)、中央値またはその他のパーセンタイルを検索できます。

このアプローチは elasticsearch と、おそらく BigQuery (QUANTILES関数の説明による)で使用されます。

10
Richard Poole

この数値セットの中央値

2、3、5、7、11、13、67、71、73、79、83、89、97

67です。

この数値セットの中央値

2、3、5、7、11、13、67、71、73、79、83、89

40です。

質問が約1,000,000,000整数(x)で、0> = x <= 2,147,483,647であり、OPが(element(499,999,999)+ element(500,000,000))/ 2(数値がソートされている場合)を探していたと仮定します。 100台すべてのコンピューターがすべて等しいと仮定した場合

ラップトップとGigEを使用して...

私が見つけたのは、私のラップトップが1.3秒で10,000,000個のInt32をソートできることです。したがって、大まかな見積もりは、10億の数の並べ替えには100 x 1.3秒(2分10秒)かかります;).

ギガビットイーサネットでの40MBファイルの一方向ファイル転送の推定は、0.32秒です。これは、すべてのコンピューターからの並べ替えられた結果が約32秒で返されることを意味します(コンピューター99は、開始後30秒までファイルを取得しませんでした)。そこから、最低の499,999,998の数字を破棄し、次の2を追加して2で除算するのに時間がかからないはずです。

5
dbasnett

これは人々を驚かせるかもしれませんが、数値が32ビット(またはそれ以下)に収まるほど小さい整数である場合-バケットソートを行うだけです!任意の数の32ビット整数に対して16GBのRAMのみが必要であり、O(n)で実行されます。 10億。

ソートされたリストを取得したら、中央値を選択するのは簡単です。実際、ソートされたリストを作成する必要はありませんが、バケットを確認するだけで作成できます。

簡単な実装を以下に示します。 16ビット整数でのみ機能しますが、32ビットへの拡張は簡単です。

#include <stdio.h>
#include <string.h>

int main()
{
    unsigned short buckets[65536];
    int input, n=0, count=0, i;

    // calculate buckets
    memset(buckets, 0, sizeof(buckets));
    while (scanf("%d", &input) != EOF)
    {
        buckets[input & 0xffff]++;
        n++;
    }

    // find median 
    while (count <= n/2)
    {
        count += buckets[i++];
    }

    printf("median: %d\n", i-1);

    return 0;
}

10億(109)数値とtimeを使用した実行

time ./median < billion

マシン1m49.293sで実行時間を生成します。実行時間のほとんどは、おそらくディスクIOです。

5
vidstige

奇妙なことに、コンピュータが十分にある場合は、O(n)中央値検出アルゴリズムを使用するよりもソートする方が良いと思います。 (ただし、コアが非常に遅い場合を除き、1つだけを使用し、O(n)中央値検出アルゴリズムを1e9の数字のみに使用します。1e12があれば、それは実用的ではないかもしれません。 )

とにかく、この問題に対処するためにlog n個以上のコアがあり、電力消費を気にせず、答えをすばやく得ると仮定しましょう。さらに、これがすべてのデータが既にメモリにロードされているSMPマシンであると仮定しましょう。 (たとえば、Sunの32コアマシンはこのタイプです。)

1つのスレッドはリストを盲目的に等しいサイズの断片に切り刻み、他のMスレッドにそれらをソートするよう指示します。これらのスレッドは、_(n/M) log (n/M)_時間で熱心にそうします。次に、中央値だけでなく、たとえば25パーセンタイルと75パーセンタイルも返します(わずかに異なる数値を選択した場合、最悪の場合は逆になります)。これで、データの範囲が4Mになりました。次に、これらの範囲を並べ替え、リスト内で上に向かって数字を見つけます。数字よりも小さい、または数字を含むeveryの範囲を捨てると、データの半分が捨てられます。それが中央値の下限です。上限についても同じことを行います。これには_M log M_時間のような時間がかかり、すべてのコアがそれを待つ必要があるため、_M^2 log M_の潜在的な時間を無駄にしています。これで、単一のスレッドが他の人に範囲外のすべてのデータを投げて(各パスで約半分を捨てる必要があります)、繰り返します-データは既にソートされているため、これは非常に高速な操作です。残りのデータを取得して標準のlog(n/M) median Finderを使用する方が高速になるまで、これをO(n)回以上繰り返す必要はありません。

したがって、総複雑度はO((n/M) log (n/M) + M^2 log M log (n/M))のようなものです。したがって、これは、説明したシナリオに当てはまるO(n)および_M^3 log M < n_の場合、1つのコアでのM >> log(n/M) medianソートよりも高速です。

これは本当に悪い考えであると思うが、それはどれほど非効率的であるかを考えると、より速い。

3
Rex Kerr

より簡単な方法は、数字に重みを付けることです。

  • 大規模なセットをコンピューター間で分割する
  • 各セットを並べ替える
  • スモールセットを反復処理し、繰り返される要素の重みを計算します
  • 各2セットを1にマージし(それぞれが既にソートされている)重みを更新する
  • セットを1つだけ取得するまでセットをマージし続けます
  • oneBillion/2に達するまでこのセットの累積ウェイトを繰り返します
2
Ziad Nasser

1台のコンピューターで問題を解決できます。

しかし、100台のコンピューターがあると仮定しましょう。あなたがすべき唯一の複雑なことは、リストをソートすることです。 100個のパーツに分割し、各コンピューターに1つのパーツを送信し、そこでソートして、その後パーツをマージします。

次に、ソートされたリストの中央から番号を取得します(つまり、インデックス5 000 000 000)。

2
Roman

これは、アルゴリズムが投票した(n log n)よりも速く実行できます。

-順序統計分散選択アルゴリズム-O(n)
ソートされていない配列でk番目の数を見つけるという元の問題を単純化します。
-ソートヒストグラムO(n)のカウント
数値の範囲についていくつかのプロパティを想定する必要があります-範囲はメモリに収まりますか? -外部マージソート-O(n log n)-上記の説明
基本的に、最初のパスで数値を並べ替えてから、2番目のパスで中央値を見つけます。
-数値の分布について何かわかっている場合は、他のアルゴリズムを作成できます。

詳細と実装については、以下を参照してください。
http://www.fusu.us/2013/07/median-in-large-set-across-1000-servers.html

2
user1712376

データに依存します。最悪のシナリオは、数字が均一に分布していることです。

この場合、O(N) timeの中央値は次の例のようになります。

番号が2,7,5,10,1,6,4,4,6,10,4,7,1,8,4,9,9,3,4,3(範囲は1-10)であると仮定します。

3つのバケットを作成します:1-3、4-7、8-10。上部と下部のサイズが等しいことに注意してください。

バケットに数字を入力し、それぞれに落ちる数、最大値、最小値を数えます

  • 低(5):2,1,1,3,3、最小1、最大3
  • 中間(10):7,5,6,4,4,6,4,7,4,4、最小4、最大7
  • 高(5):10、10、8、9、9、最小8、最大10

平均は真ん中のバケツに落ち、残りは無視します

4つのバケット、4、5〜6、7を作成します。低は5のカウントで開始し、最大は3で、最小は8でカウントは5です。

各数について、低バケットと高バケット、最大バケットと最小バケットに落ちる数をカウントし、中間バケットを保持します。

  • オールドロー(5)
  • 低(5):4、4、4、4、4、4、最大4
  • 中間(3):5,6,6
  • 高(2):7、7、最小7
  • オールドハイ(5)

これで中央値を直接計算できます:このような状況があります

old low    low          middle  high  old high
x x x x x  4 4 4 4 4 4   5 6 6  7 7   x x x x x

したがって、中央値は4.5です。

分布について少し知っていると仮定すると、速度を最適化するために範囲を定義する方法を微調整できます。いずれの場合でも、1 + 1/3 + 1/9 ... = 1.5なので、パフォーマンスはO(N)で行く必要があります。

エッジの場合のために、最小値と最大値が必要です(たとえば、中央値が古い低値の最大値と次の要素の平均値である場合)。

これらの操作はすべて並列化でき、データの100分の1を各コンピューターに渡し、各ノードで3つのバケットを計算してから、保持しているバケットを配布できます。この場合も、各数値が平均1.5回渡されるため(O(N))、ネットワークを効率的に使用できます。ノード間で最小数だけを渡す場合(たとえば、ノード1に100個の番号があり、ノード2に150個の番号がある場合、ノード2はノード1に25個の番号を与えることができます)。

分布について詳しく知らない限り、実際に少なくとも1回は要素を数える必要があるため、ここでO(N)よりも良いことはできないと思います。

2
Sklivvz

これは、ノード間で(たとえば、ログファイルから)ソートされていないデータを使用して、次の方法でノードで実行できます。

1つの親ノードと99の子ノードがあります。子ノードには2つのAPI呼び出しがあります。

  • stats():min、max、countを返します
  • compare(median_guess):一致する値のカウント、値未満のカウント、値より大きいカウントを返します

親ノードは、すべての子ノードでstats()を呼び出し、すべてのノードの最小値と最大値に注目します。

現在、バイナリ検索は次の方法で実行できます。

  1. 最小と最大の切り捨てを二等分する-これは中央値「推測」です
  2. 「より大きい」カウントが「より小さい」カウントより大きい場合、最小値を推測に設定します
  3. 「より大きい」カウントが「より小さい」カウントよりも小さい場合は、推測に最大値を設定します
  4. 最小値と最大値が等しいときにカウントが奇数で終了する場合
  5. 最大<=最小+ guess.match_countのときにカウントが終了する場合これは、ソートされていないデータ(ログファイルなど)を使用するノードで次のように実行できます。

1つの親ノードと99の子ノードがあります。子ノードには2つのAPI呼び出しがあります。

  • stats():min、max、countを返します
  • compare(median_guess):一致する値のカウント、値未満のカウント、値より大きいカウントを返します

親ノードは、すべての子ノードでstats()を呼び出し、すべてのノードの最小値と最大値に注目します。

現在、バイナリ検索は次の方法で実行できます。

  1. 最小と最大の切り捨てを二等分する-これは中央値「推測」です
  2. 「より大きい」カウントが「より小さい」カウントより大きい場合、最小値を推測に設定します
  3. 「より大きい」カウントが「より小さい」カウントよりも小さい場合は、推測に最大値を設定します
  4. 最小値と最大値が等しいときにカウントが奇数で終了する場合
  5. 最大<=最小+ guess.match_countのときにカウントが終了する場合

O(N/Mlogn/M)並べ替えでstats()およびcompare()を事前計算できる場合は、O(N/M)事前計算で事前計算のためのO(N)のメモリの複雑さ。その後、一定の時間でcompare()を実行できるため、全体(事前計算を含む)がO(N/MlogN/M)+ O(logN)で実行されます

間違えた場合は教えてください!

1
teambob

10 ^ 9の数字、10 ^ 7を各コンピューターに分割して、それぞれ80MBまで。各コンピューターはその番号を並べ替えます。次に、コンピューター1は、コンピューター2、コンピューター3、4などの番号と自分の番号をマージソートします。その後、コンピューター1は、数字の半分を2、3〜4などに書き戻します。 1,2,3,4、それらを書き戻します。等々。 RAMのサイズに応じて、各ステップで個々のコンピューターにすべての数字を書き戻さなくても済む可能性があります。手順ですが、あなたは数学を行います。

ああ、最後に500000000番目と500000001番目の値の平均を取得します(ただし、十分な00があることを確認しますが、まだありません)。

編集:@Roman-それが真実であっても信じられないなら、命題の真実または虚偽を明らかにすることには意味がありません。私が言いたいことは、ブルートフォースが時々レースでスマートに勝つということでした。実装できると確信しており、機能し、さまざまなサイズの入力とコンピューターの数に適応でき、コンピューターの特性に調整可能なアルゴリズムを考案するのに約15秒かかりましたネットワーキングの手配。あなたや他の誰かが、より洗練されたアルゴリズムを考案するのに15分かかる場合、私のソリューションをコーディングして実行するのに14分45秒の利点があります。

しかし、これはすべて断言であり、何も測定していません。

スティーブジェソップの答えは最速だと思います。

ネットワークデータ転送サイズがボトルネックである場合、別のアプローチがあります。

Divide the numbers into 100 computers (10 MB each). 
Loop until we have one element in each list     
    Find the meadian in each of them with quickselect which is O(N) and we are processing in parallel. The lists will be partitioned at the end wrt median.
    Send the medians to a central computer and find the median of medians. Then send the median back to each computer. 
    For each computer, if the overall median that we just computed is smaller than its median, continue in the lower part of the list (it is already partitioned), and if larger in the upper part.
When we have one number in each list, send them to the central computer and find and return the median.
0
Cem

中央値を見つけるためにトーナメントツリーメソッドを使用できます。各リーフノードが配列になるように、1000個のリーフノードを持つツリーを作成できます。次に、異なる配列間でn/2トーナメントを実施します。n/ 2トーナメント後のルートの値が結果です。

http://www.geeksforgeeks.org/tournament-tree-and-binary-heap/

0
karan kapoor

さて、異なる整数の数が(たとえば)40億であることを知っていると仮定すると、それらを64kのバケットにバケットし、クラスター内の各マシン(100台のコンピューター)から各バケットの分散カウントを取得できます。これらすべてのカウントを結合します。ここで、中央値を持つバケットを見つけます。今回は、ターゲットバケットにある64k要素のバケットのみを要求します。これには、O(1)(特に2)の「クラスター」に対するクエリが必要です。):D

0
gandharv garg

私のペニーの価値は、すべて他の人によってすでに育てられたものです。

単一のマシンで中央値を見つけるのはO(N)です: https://en.wikipedia.org/wiki/Selection_algorithm

N個の数字を100台のマシンに送信することもO(N)です。したがって、100台のマシンの使用を面白くするには、通信が比較的高速であるか、Nが非常に大きいためにN/100が実行可能であるのに1台のマシンで処理できないか、または気にせずに数学的問題を検討する必要がありますデータ通信。

短くするために、合理的な制限内で、効率分析に影響を与えずに数値を送信/配布できると仮定します。

次に、一般的な処理の「マスター」として1台のマシンが割り当てられる次のアプローチを検討してください。これは比較的高速であるため、「マスター」は各マシンが実行する一般的なタスクにも参加します。

  1. 各マシンはN/100の数値を受信し、独自の中央値を計算して、その情報をマスターに送信します。
  2. マスターは、すべての異なる中央値のソートされたリストをコンパイルし、それを各マシンに送り、バケットの順序シーケンス(各マシンで同じ)を定義します。隣接する中央値。もちろん、中央値が最低値を下回り、最高値を上回る値には、ローエンドバケットとハイエンドバケットもあります。
  3. 各マシンは、各バケットに含まれる数値の数を計算し、その情報をマスターに返します。
  4. マスターは、どのバケットに中央値が含まれるか、そのバケットを下回る(合計で)低い値の数、およびそのバケットを下回る数を決定します。
  5. 選択されたバケットが単一値バケット(中央値の1つ)である場合、選択されたバケットに含まれる値は1(奇数N)または2(偶数N)のみです。それ以外の場合は、次の(明らかな)変更を加えて上記の手順を繰り返します。
  6. 選択したバケットの番号のみが、マスターから100台のマシンに(再)配布され、さらに
  7. (各マシンで)中央値を計算するのではなく、k番目の値を計算します。ここでは、合計から破棄された上位の数と下位の数を考慮します。概念的には、各マシンは破棄された低/高数値のシェアも持ち、破棄された数値を(概念的に)含むセットの新しい中央値を計算するときにそれを考慮します。

時間の複雑さ:

  1. 少し考えてみると、各ステップで分析する値の合計数が少なくとも2分の1に減少することを確信できます(2はかなり病気のケースです。大幅に改善されるはずです)。これから次のようになります。
  2. O(N)である中央値(またはk番目の値)を見つけるにはc * N時間がかかると仮定します。ここで、プリファクターcはNであまり変化しないので、現時点では定数として使用できます。 '最大2 * c * N/100時間で最終結果を取得します。したがって、100台のマシンを使用すると、100/2(少なくとも)の高速化係数が得られます。
  3. 最初に述べたように、マシン間で番号を通信するのにかかる時間は、1台のマシンですべてを単純に行う方が魅力的かもしれません。ただし、分散アプローチを採用する場合、すべてのステップで一緒に通信される数の合計数は2 * N(最初のN、2回目の<= N/2、その半分の< 3番目など)。
0
Bert te Velde

最初に、1台のマシンでn個の数値の中央値を見つける方法を考えてみましょう。基本的にパーティション戦略を使用しています。

問題:selection(n、n/2):最小の番号からn/2番目の番号を見つけます。

たとえば、中間要素kを選択し、データを2つのサブ配列に分割します。 1番目にはすべての要素<kが含まれ、2番目にはすべての要素> = kが含まれます。

sizeof(1st sub-array)> = n/2の場合、このサブ配列には中央値が含まれていることがわかります。その後、2番目のサブ配列を捨てることができます。この問題を解決してくださいselection(sizeof 1st sub-array、n/2)

それ以外の場合は、この最初のサブ配列を捨てて、selection(2nd subarray、n/2-sizeof(1st subarray))を解きます

再帰的に実行します。

時間の複雑さは O(n)予想時間。

多数のマシンがある場合、各反復で配列を処理して分割する必要があり、配列をdiffマシンに分散します。各マシンは配列のチャンクを処理し、ハブ制御マシンにサマリーを送り返します。つまり、1番目のサブアレイのサイズと2番目のサブアレイのサイズです。ハブマシンはサマリーを加算し、どのサブアレイ(1番目または2番目)選択の第2パラメータをさらに処理し、各マシンに送り返します。等々。

このアルゴリズムはmap reduceを使用して非常にきれいに実装できますか?

どのように見えますか?

0
xyz

これはどうですか:-各ノードは10億個/ 100個の番号を取ることができます。各ノードで要素をソートし、中央値を見つけることができます。中央値の中央値を見つけます。すべてのノードで中央値の中央値より小さい数のカウントを集計することにより、中央値の中央値が作成するx%:y%分割を見つけることができます。ここで、中央値の中央値よりも小さい要素を削除するようにすべてのノードに依頼します(30%:70%の分割を例に取る)。30%の数字が削除されます。 10億の70%は7億です。 300万未満のノードを削除したすべてのノードは、これらの追加ノードをメインコンピューターに送り返すことができます。メインコンピューターは、すべてのノードがほぼ同じ数のノード(700万)を持つように再配布します。問題が7億個に減少したので、1つのcompで計算できる小さなセットができるまで続きます。

0
anony

番号が明確ではなく、特定の範囲にのみ属している場合、つまり繰り返されている場合、私の頭に浮かぶ簡単な解決策は、99台のマシンに均等に番号を分配し、1台のマシンをマスターとして維持することです。これで、すべてのマシンが指定された数値を反復処理し、各数値のカウントをハッシュセットに保存します。その特定のコンピューターに割り当てられた数字のセットで数字が繰り返されるたびに、ハッシュセットのカウントが更新されます。

その後、すべてのマシンがハッシュセットをマスターマシンに返します。マスターマシンはハッシュセットを結合し、ハッシュセットで見つかった同じキーのカウントを合計します。たとえば、machine#1のハッシュセットには( "1"、7)のエントリがあり、machine#2のハッシュセットには( "1"、9)のエントリがあったため、ハッシュセットを結合するときのマスターマシンのエントリは(「1」、16)など。

ハッシュセットがマージされたら、キーを並べ替えるだけで、並べ替えられたハッシュセットから(n/2)番目のアイテムと(n + 2/2)番目のアイテムを簡単に見つけることができます。

この方法は、10億個の数字が異なる場合には有益ではありません。

0
Eric B.

私はこのようにします:

最初は、100個すべての作業で最高数と最低数を見つけます。各コンピューターには、照会するデータベース/ファイルの一部があります。

最大値と最小値が見つかると、1台のコンピューターがデータを読み取り、99の残りの部分に各番号を均等に分配します。番号は等間隔で分配されます。 (1つは-100百万から0、もう1つは0から1億など)。

数字を受け取っている間、99台のコンピューターのそれぞれが既に数字を並べ替えています。

次に、中央値を見つけるのは簡単です...各コンピューターにある数字の数を確認し、それらすべてを追加します(数字自体ではなく、数字の数の合計)、2で除算します。どのコンピューターが数字で、どのインデックスであるかを計算します。

:)ボイラ

追伸ここには多くの混乱があるようです。中央値-番号のソートされたリストの中の番号です!

0
Ion