4

mongodb 用のカスタム クエリ ビルダーが必要です。クエリに使用できるドキュメント (フィールド) のリストを表示するユーザー インターフェイスは既に作成済みです。ユーザーは、「結果列」、「条件」、「グループ化」、および「並べ替え」を選択できます。SQL言語を使用して説明しましょう..例を見てください:

SELECT col1, col2 FROM table WHERE col1=1 AND col2="foo" OR col3 > "2012-01-01 00:00:00" OR col3 < "2012-01-02 00:00:00" AND col5 IN (100, 101, 102) GROUP BY col4, col5 ORDER BY col1 DESC, col2 ASC

それで

  • SELECT col1, col2 -- 結果列
  • WHERE col1=1 AND col2="foo" OR col3 > "2012-01-01 00:00:00" OR col3 < "2012-01-02 00:00:00" -- 条件
  • GROUP BY col4、col5 -- グループ化ステートメント
  • ORDER BY col1 DESC, col2 ASC -- order by ステートメント

列数、条件、グループ化、および順序付けは、ユーザー インターフェイスで使用されるによって送信された JSON データに基づいて、Python によって生成される必要があります。

MapReduce を使用して mongoDB でそれを行うことができるかどうかに興味がありますか? そのためのモジュールを見たことがありますか?また、MongoDB に詳しい方は、この SQL クエリを MongoDB クエリに翻訳していただけませんか?

4

2 に答える 2

6

最も単純な (そして最もスケーラブルな) ソリューションは、おそらくフィルタリング条件を MongoDB クエリに変換し、クライアント側で集計を行うことです。

上記の例を取り上げて、それを分解して MongoDB クエリを作成しましょう ( PyMongoを使用してこれを示しますが、必要に応じて Mongoengine または別の ODM を使用して同じことを行うこともできます)。

WHERE col1=1 AND col2="foo" OR col3 > "2012-01-01 00:00:00" OR col3 < "2012-01-02 00:00:00" -- 条件

これは、PyMongo のfind()メソッドの最初の引数です。$or演算子を使用して論理 AND/OR ツリーを明示的に構築する必要があります。

from bson.tz_util import utc
cursor = db.collection.find({'$or': [
    {'col1': 1, 'col2': 'foo'},
    {'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
    {'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]})

日付/時刻フィールドと比較する場合、MongoDB は文字列を日付に変換しないことに注意してください。したがって、ここでは Pythondatetimeモジュールを使用して明示的に変換しています。そのモジュールのdatetimeクラスは、指定されていない引数のデフォルト値として 0 を想定しています。

SELECT col1, col2 -- 結果列

フィールド選択を使用して、必要なフィールドのみを取得できます。

from bson.tz_util import utc
cursor = db.collection.find({'$or': [
    {'col1': 1, 'col2': 'foo'},
    {'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
    {'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2'])

GROUP BY col4、col5 -- グループ化ステートメント

これは、標準の MongoDB クエリを使用して効率的に実行することはできません (ただし、新しいAggregation Frameworkを使用してサーバー側でこれをすべて実行する方法についてはすぐに説明します)。代わりに、これらの列でグループ化したいことがわかっているので、これらのフィールドで並べ替えることで、アプリケーション コードをより単純にすることができます。

from bson.tz_util import utc
from pymongo import ASCENDING
cursor = db.collection.find({'$or': [
    {'col1': 1, 'col2': 'foo'},
    {'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
    {'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2', 'col4', 'col5'])
cursor.sort([('col4', ASCENDING), ('col5', ASCENDING)])

ORDER BY col1 DESC, col2 ASC -- order by ステートメント

これは、必要な集計関数を適用した後にアプリケーション コードで実行する必要があります (col4 を合計し、col5 の最大値を取得するとします)。

from bson.tz_util import utc
from pymongo import ASCENDING
cursor = db.collection.find({'$or': [
    {'col1': 1, 'col2': 'foo'},
    {'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
    {'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2', 'col4', 'col5'])
cursor.sort([('col4', ASCENDING), ('col5', ASCENDING)])

# groupby REQUIRES that the iterable be sorted to work 
# correctly; we've asked Mongo to do this, so we don't
# need to do so explicitly here.
from itertools import groupby
groups = groupby(cursor, keyfunc=lambda doc: (doc['col1'], doc['col2'])
out = []
for (col1, col2), docs in groups:
    col4sum = 0
    col5max = float('-inf')
    for doc in docs:
        col4sum += doc['col4']
        col5max = max(col5max, doc['col5'])
    out.append({
        'col1': col1,
        'col2': col2,
        'col4sum': col4sum,
        'col5max': col5max
    })

集約フレームワークの使用

MongoDB 2.1 以降を使用している場合 (2.1.x は、まもなく予定されている 2.2.0 安定版リリースに向けた開発シリーズです)、Aggregation Framework を使用して、サーバー側でこれらすべてを実行できます。これを行うには、次のaggregateコマンドを使用します。

from bson.son import SON
from pymongo import ASCENDING, DESCENDING
group_key = SON([('col4', '$col4'), ('col5': '$col5')])
sort_key = SON([('$col1', DESCENDING), ('$col2', ASCENDING)])
db.command('aggregate', 'collection_name', pipeline=[
    # this is like the WHERE clause
    {'$match': {'$or': [
        {'col1': 1, 'col2': 'foo'},
        {'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
        {'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
        ]}},
    # SELECT sum(col4), max(col5) ... GROUP BY col4, col5
    {'$group': {
        '_id': group_key,
        'col4sum': {'$sum': '$col4'},
        'col5max': {'$max': '$col5'}}},
    # ORDER BY col1 DESC, col2 ASC
    {'$sort': sort_key}
])

このaggregateコマンドは、MongoDB の通常の制限の対象となる BSON ドキュメント (つまり、Python 辞書) を返します。返されるドキュメントのサイズが 16MB を超える場合、コマンドは失敗します。さらに、メモリ内$sortの並べ替え (この集計の最後に によって必要とされる) の場合、並べ替えがサーバー上の物理 RAM の 10% を超える必要がある場合、集計フレームワークは失敗します (これは、コストのかかる集計が削除されるのを防ぐためです)。 Mongo がデータ ファイルに使用するすべてのメモリ)。

于 2012-04-18T14:43:47.497 に答える
1

そして、あなたの問題は何ですか。もちろん、これらのクエリを Mongo に対して行うことができ、mapreduce は何の関係もありません。Mongo をすぐに使いたい場合は、mongoengineのような ORM を試すことができます。

于 2012-04-18T13:25:30.640 に答える