大量の情報を収集し、Mongo データベースに生の形式で保存するプログラムをいくつか作成しました。その後、事前に指定された期間に、map_reduce
この情報のサブセットを評価する操作が呼び出されます。
生データは保持する必要があり、破棄することはできませんが、map_reduce
操作を実行するために必ずしも生データ全体の結果が必要なわけではありません。代わりに、map_reduce
まだ評価されていない最新の収集データに対してのみ実行できるように操作を構築しました。2 番目のmap_reduce
操作が後で呼び出され、洗練された生データの削減が処理されます。
map_reduce
次に、一度削減された生データが各操作で削減されないようにクエリ フィルターを指定する必要があります。私が遭遇した解決策は、フィルターを指定する(またはmap_reduce
操作にクエリを渡す)ことでした。これにより、所定の日付よりも新しいdate_collectedフィールドを持つエントリのみが選択されます。
まず、次のコードを使用しようとしました。
for k in SomeData.objects.filter(date_collected__gt=BULK_REQUEST_DATE).map_reduce(map_f, reduce_f, {'merge':'COLLECTION'}):
print k.value
また、これを「より小さい」フィルターで試しました(日付を逆に考えていないことを確認するため)。それもうまくいきませんでした。
ここで興味深いのは次のとおりです。map_reduce 連鎖メソッド呼び出しを削除して、上から出力するとしたら、次のようになりますk
。
for k in SomeData.objects.filter(date_collected__gt=BULK_REQUEST_DATE):
print k
フィルターは問題なく機能し、特定の時点以降に収集されたデータのみが選択されます。
次に、MongoEnginequeryset.py
モジュールをハッキングし、オプションのパラメーターをmap_reduce
メソッドに追加して、次のようにクエリをmap_reduce
関数に渡すことができるようにしました。
q = {'date_collected' : {'$lte' : BULK_REQUEST_DATE}}
for k in SomeData.objects.filter(date_collected__lte=BULK_REQUEST_DATE).map_reduce(map_f, reduce_f, {'merge':'COLLECTION'}, query=q):
print k.value
繰り返しますが、これは期待される結果を生み出すことができませんでした。ただし、エラーはありませんでした。不適切に構成されたクエリを渡すか、高度なクエリ演算子を のようなものに変更することで操作を中断することができたので、メソッドに渡したクエリが評価され、少なくとも問題は発生していないことがわかります。 .map_reduce
$lte
$asdfjla
map_reduce
操作を実行する上記のすべての方法を通じてmap_reduce
、生ストレージ内のすべてのデータ全体が評価されました。私の試みはどれも map_reduce 操作を壊しませんでしたが、クエリをデータのサブセットに制限することにも失敗しました。
誰かが日付を比較するための私のロジックの欠陥を指摘できますか?
日付は mongo データベースに python datetime.time として保存されます。また、2 つの日付を比較する前に、日付を ISOformat に変更してみました。これは、python または javascript 側では機能しませんでした。
どんな助けでも大歓迎です!ありがとうございました。
アップデート
問題は MongoEngine にはないと判断しました。
この問題は、"$gte" や "$lte" などの演算子を使用して JavaScript で PyMongo Datetime オブジェクトを比較する方法に関連しています。何らかの理由で、datetime オブジェクトがそのように扱われないか、JavaScript の日付に正しく変換されません。
私はまだこれ以上のことを理解できていませんが、もし何か指針があれば、きっとそれらを使うことができます!
アップデート
MongoEngine のテストから PyMongo の直接テストに移行しました。次のコードは、期待される結果を生成できません。注: epochtime は、ドキュメントが作成されたエポックからの秒数 (整数) を含むフィールドです。Timestamp も int であり、実行時に作成されます。
j = db.data.map_reduce(map_f, reduce_f, {'merge':'COLLECTION'}, query={'epochtime':{'$lte':timestamp}})
for x in j.find():
print x
"$lte" を使用すると、タイムスタンプ > エポックタイムが常に続くため、for ループで x が出力されることが予想されます。あるいは、「$gte」が使用された場合、値は出力されないと予想されます。代わりに、両方の発生で同じ値が出力されます。「$lte」または「$gte」演算子を使用する場合に違いはありません。
私は何が欠けていますか?
アップデート
前回の更新と同じ操作を適用しました。エポックからの秒数の代わりに、コレクション内の各エポックタイム フィールドを 1 から始まる増分値になるようにリセットしました。タイムスタンプ = 1 も設定しました。その後、実行しました。 map_reduce 操作。正しく動作しました。
これは、フィールドのバイトサイズに問題があると思いますか? float フィールドを使用して上記の結果を再現しました。小さな浮動小数点数では機能しましたが、エポック以降の秒数を表す浮動小数点数 (小数を含む) では機能しませんでした。
私は間違いなくここで基本的な何かを欠いています...
アップデート
問題を引き起こしている可能性のあるものを見つけました。map_reduce のマージ出力関数を使用すると、クエリに基づいて正常にフィルター処理され、削減されたデータが指定されたコレクションに最初に保存されます。ただし、これは一度しか機能しません。あとで言えば、クエリの条件は一貫して機能しません。これはマージ出力関数でのみ発生するようです。replace、reduce、または inline 出力メソッドを使用する場合は発生しません。さらに、マージ関数が同じセットで 2 度目に使用されると、クエリ引数の条件は、比較される 2 つの値のサイズに依存するようです - 前の更新を参照してください。
これが何を意味するのか、なぜこれが起こるのか、私にはわかりません。