web-dev-qa-db-ja.com

1000以上を取得する方法は?

データストアから1000を超えるレコードをフェッチし、すべてを1つのリストに入れてdjangoに渡すにはどうすればよいですか?

49
Zote

バージョン1.3.6(2010年8月17日リリース)以降、あなた[〜#〜]できます[〜#〜]

変更ログから:

データストアcount()クエリの結果およびすべてのデータストアクエリのオフセットは、1000で制限されなくなりました。

37
Shay Erlichmen

記録のためだけに-1000エントリのフェッチ制限がなくなりました。

http://googleappengine.blogspot.com/2010/02/app-engine-sdk-131-include-major.html

引用:

1000件の結果の制限はありません-そうです。カーソルの追加と、過去数か月にわたる多くの小さなDatastoreの安定性とパフォーマンスの向上の集大成により、最大の結果の制限を完全に取り除くのに十分です。フェッチ、反復、またはCursorを使用している場合でも、結果の数に制限はありません。

23

App Engineでは、キーで順序付けし、最後のキーを次のオフセットとして使用することにより、結果を1000ずつ「ページング」する優れた方法を提供しています。彼らはここにいくつかのサンプルコードを提供しています:

http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html#Queries_on_Keys

これらの例ではクエリを多くのリクエストに分散していますが、ページサイズを20から1000に変更して、ループでクエリセットを組み合わせてクエリを実行できます。さらに、itertoolsを使用して、必要になる前にクエリを評価せずにリンクすることもできます。

たとえば、1000を超える行数を数えるには:

class MyModel(db.Expando):
    @classmethod
    def count_all(cls):
        """
        Count *all* of the rows (without maxing out at 1000)
        """
        count = 0
        query = cls.all().order('__key__')

        while count % 1000 == 0:
            current_count = query.count()
            if current_count == 0:
                break

            count += current_count

            if current_count == 1000:
                last_key = query.fetch(1, 999)[0].key()
                query = query.filter('__key__ > ', last_key)

        return count
19
JJ Geewax

これが制限として現れるたびに、「なぜ1,000以上の結果が必要ですか?」 Google自体が1,000件を超える結果を提供していないことをご存知ですか?次の検索を試してください: http://www.google.ca/search?hl=en&client=firefox-a&rls=org.mozilla:en-US:official&hs=qhu&q=1000+results&start=1000&sa=N クエリの検索結果の100番目のページをクリックするのに時間がかからなかったので、最近までそのことを知りませんでした。

実際に1,000を超える結果をユーザーに返している場合は、データストアで許可されていないという事実よりも大きな問題があると思います。

多くの結果が必要になる可能性のある(正当な)理由の1つは、データに対して大規模な操作を実行し、要約(たとえば、このすべてのデータの平均値)を提示している場合です。この問題(Google I/Oトークで説明されています)の解決策は、要約データを即座に計算し、それを保存することです。

18
Tony Arkles

できません。

FAQの一部は、クエリの行1000を超えてアクセスできる方法はないと述べています。「OFFSET」を増やすと、結果セットが短くなります。

つまり、OFFSET 999-> 1つの結果が返されます。

ウィキペディアから:

App Engineは、エンティティから返される最大行数を、データストア呼び出しあたり1000行に制限します。ほとんどのWebデータベースアプリケーションはページングとキャッシングを使用しているため、一度にこれほど多くのデータを必要としないため、ほとんどのシナリオでこれは問題になりません。独自のクライアント側ソフトウェアまたはAjaxページを使用して、無制限の行数で操作を実行できます。

http://code.google.com/appengine/docs/whatisgoogleappengine.html から

サービス制限の別の例は、クエリによって返される結果の数です。クエリは最大1,000件の結果を返すことができます。より多くの結果を返すクエリは、最大値のみを返します。この場合、そのようなクエリを実行するリクエストは、タイムアウト前にリクエストを返す可能性は低いですが、データストア上のリソースを節約するために制限が設けられています。

From http://code.google.com/appengine/docs/datastore/gqlreference.html から

注:LIMIT句の最大値は1000です。最大値より大きい制限が指定されている場合、最大値が使用されます。これと同じ最大値がGqlQueryクラスのfetch()メソッドに適用されます。

注:fetch()メソッドのオフセットパラメータと同様に、GQLクエリ文字列のOFFSETは、データストアからフェッチされるエンティティの数を減らしません。 fetch()メソッドによって返される結果にのみ影響します。オフセットのあるクエリには、オフセットサイズに線形に対応するパフォーマンス特性があります。

http://code.google.com/appengine/docs/datastore/queryclass.html から

Limitおよびoffset引数は、データストアからフェッチされる結果の数、およびfetch()メソッドによって返される結果の数を制御します。

  • データストアは、オフセット+制限の結果をアプリケーションにフェッチします。最初のオフセット結果は、notであり、データストア自体によってスキップされます。

  • Fetch()メソッドは、最初のオフセット結果をスキップしてから、残り(制限結果)を返します。

  • クエリには、オフセット量に制限を加えたものに線形に対応するパフォーマンス特性があります。

これが意味することは

単一のクエリがある場合、0〜1000の範囲外を要求する方法はありません。

オフセットを増やすと0が増えるだけなので、

LIMIT 1000  OFFSET 0    

1000行を返します、

そして

LIMIT 1000 OFFSET 1000 

0行を返すため、単一のクエリ構文では、手動またはAPIを使用して2000件の結果をフェッチすることができません。

唯一のもっともらしい例外

テーブルに数値インデックスを作成することです。つまり、

 SELECT * FROM Foo  WHERE ID > 0 AND ID < 1000 

 SELECT * FROM Foo WHERE ID >= 1000 AND ID < 2000

データまたはクエリがこの「ID」ハードコードされた識別子を持つことができない場合、あなたは運が悪い

14
Kent Fredric

この1K制限の問題は解決されました。

query = MyModel.all()
for doc in query:
    print doc.title

Queryオブジェクトを反復可能として処理することにより、イテレータはデータストアから小さなバッチで結果を取得し、アプリが結果の反復を停止して、必要以上のフェッチを回避できるようにします。クエリに一致するすべての結果が取得されると、反復が停止します。 fetch()と同様に、イテレータインターフェースは結果をキャッシュしないため、Queryオブジェクトから新しいイテレータを作成すると、クエリが再実行されます。

最大バッチサイズは1Kです。また、自動データストアの割り当ても残っています。

しかし、1.3.1 SDKプランでは、シリアル化して保存できるカーソルを導入しているため、将来の呼び出しで、最後に中断したところからクエリを開始できます。

10
Tiger Woods

1000レコードの制限は、Google AppEngineのハード制限です。

このプレゼンテーション http://sites.google.com/site/io/building-scalable-web-applications-with-google-app-engine では、AppEngineを使用してデータを効率的にページングする方法について説明しています。

(基本的に、数値IDをキーとして使用し、IDにWHERE句を指定します。)

7
jakber

1000を超えるレコードがある場合でも、リモートAPIを介したフェッチには問題があります。チャンクでテーブルを反復処理するこの小さな関数を作成しました。

def _iterate_table(table, chunk_size = 200):
    offset = 0
    while True:
        results = table.all().order('__key__').fetch(chunk_size+1, offset = offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size+1:
            break
        offset += chunk_size
6
Tzach

ModelBaseクラスで次のものを使用しています。

@classmethod
def get_all(cls):
  q = cls.all()
  holder = q.fetch(1000)
  result = holder
  while len(holder) == 1000:
    holder = q.with_cursor(q.cursor()).fetch(1000)
    result += holder
  return result

これにより、すべてのモデルで1000クエリの制限を回避できます。鍵バージョンの実装も同じくらい簡単だと思います。

3
Gabriel
entities = []
for entity in Entity.all():
    entities.append(entity)

そのような単純な。チャンクでフェッチするよりもはるかに遅いすべてのエンティティに対して作成されたRPCがあることに注意してください。したがって、パフォーマンスが気になる場合は、次の手順を実行します。

アイテムが100万個未満の場合:

entities = Entity.all().fetch(999999)

それ以外の場合は、カーソルを使用します。

次の点にも注意してください。

Entity.all().fetch(Entity.all().count())

最大1000を返すため、使用しないでください。

2
crizCraig
class Count(object):
def getCount(self,cls):
    class Count(object):
def getCount(self,cls):
    """
    Count *all* of the rows (without maxing out at 1000)
    """
    count = 0
    query = cls.all().order('__key__')


    while 1:
        current_count = query.count()
        count += current_count
        if current_count == 0:
            break

        last_key = query.fetch(1, current_count-1)[0].key()
        query = query.filter('__key__ > ', last_key)

    return count
2
fun_vit

JJG:上記のソリューションは素晴らしいですが、レコードが0の場合に無限ループが発生する点が異なります。 (一部のレポートをローカルでテストしているときにこれがわかりました)。

Whileループの開始を次のように変更しました。

while count % 1000 == 0:
    current_count = query.count()
    if current_count == 0:
        break
1
mhawthorne

2つのクエリの内容を一緒に追加するには:

list1 = first query
list2 = second query
list1 += list2

リスト1には2000件の結果がすべて含まれています。

0
Tom Leys

これは、Gabrielが提供するソリューションに近いものですが、カウントするだけで結果を取得しません。

count = 0
q = YourEntityClass.all().filter('myval = ', 2)
countBatch = q.count()
while countBatch > 0:
    count += countBatch
    countBatch = q.with_cursor(q.cursor()).count()

logging.info('Count=%d' % count)

私のクエリに対して完全に機能し、高速でもあります(67秒のエンティティをカウントするのに1.1秒)

クエリが不等式フィルターまたはセットであってはなりません。そうでないと、カーソルが機能せず、次の例外が発生します。

AssertionError:マルチクエリで使用できるカーソルがありません( "IN"または "!="演算子を使用したクエリ)

0
Timothy Tripp

NDBを使用している場合:

@staticmethod
def _iterate_table(table, chunk_size=200):
    offset = 0
    while True:
        results = table.query().order(table.key).fetch(chunk_size + 1, offset=offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size + 1:
            break
        offset += chunk_size
0
Oded Breiner

提案されたソリューションは、エントリがキーでソートされている場合にのみ機能します...最初に別の列でソートしている場合でも、limit(offset、count)句を使用する必要がありますが、1000エントリの制限が引き続き適用されます。最初のリクエストは1000個を超えるキーを返すことができないため、2つのリクエストを使用する場合も同じです。 (Google キーのクエリセクションでは、keyでソートして1000件の結果の制限を削除する必要があるかどうかを明確に述べていません)

0
cjed