1

ユーザーがページをめくるアイテムのリストがあるアプリケーションがあります。私はインデックスフィールドを介してページングを処理しました(とにかく他の目的でそれが必要だったので、なぜそうしないのか考えました)。

私の問題は、「goto」機能を実装したいということです。ユーザーは、提供されているナビゲーションボタン(次と前)を使用してアイテムをページングする代わりに、アイテムに直接スキップできます。たとえば、「goto」ボックスに1000と入力して、1000番目のアイテムを表示することができます。n番目のアイテムとそのインデックスの間には断絶があります。インデックスは正しいことが保証されていますが、連続しているとは保証されていないため、インデックスでフィルタリングすることはできません。offsetのパラメータを使用することを考えましたfetchが、appengineを使用してプログラミングを始めたとき、パフォーマンスの問題のために使用しないように言われたことを覚えています。

ここに行くのに最適な方法でしょうかoffset、それとももっと良い方法がありますか?また、それに関連するコストは、結果を取得するのに時間がかかるという単純なものですか、それともデータストアの読み取り/小規模な操作にカウントされますか?

編集:私はこれを悪い意味ではありませんが、カーソルを使用するように私に言う人々を食い止めるために...:-)私は私が使用する場合よりも便利な方法でページングを処理しますカーソル。よろしくお願いします。さらに、私がやろうとしていることをコードで少し詳しく説明しようと思いました。

q = Item.all()
#orders it by highest index first which is how client handles items
q = q.order('-index') 
#count is determined automatically but is at least 25 and not greater than 300
q = q.fetch(limit=count, offset=i) 

編集2: コメントに基づいて、アイテムをmemcacheに保存し、フィルタリング、順序付け、オフセットなどのすべてをメモリに保存することにしました。は最大1500個のアイテムを保持できるItemグループ化されており、それぞれを独自のキーでmemcacheに保存します。私が考えることができる唯一の問題は、それぞれが最悪の場合のシナリオのサイズが2kbになる可能性があるということです。aが1500に近い場所にある可能性は低く、最悪のシナリオサイズに達する可能性は低いですが、そうなると、1MBのmemcache制限を超えます。それを処理する方法について何か提案はありますか?また、約10個ある可能性があります。memcacheにこれだけ多くのストレージがあると、より頻繁にフラッシュされますか?そして最後に、私がフェッチするときにオフセットを使用することは価値がありますか?CategoryCategoryItemCategoryItemsItemCategoriesEntitiesまたは、memcacheの方が優れたソリューションItemsですか(通常は小グループ(25〜30)で非常に頻繁にアクセスされます)?

編集3: アイテムを順番に参照する方法ができました。各アイテムには、カテゴリ間で一意に識別するID、カテゴリ内のアイテムを非順次に並べ替える方法であるインデックス、および順次であるがアイテムに暗黙的ではないnumがあります(アイテムを引き出すたびにmemcacheインデックスで並べ替えてから、アイテムのリストを繰り返し処理し、各アイテムに現在の反復回数を指定してnumを割り当てます)これは複雑な言い方だと思います。

for i in range(0, len(items)):
    items[i]['num'] = i

編集4: アイテムモデル:

class Item(db.Model):
   item_id = db.IntegerProperty()
   index = db.IntegerProperty()
   #I used StringProperty instead of ReferenceProperty because I'm a cheapo with memory 
   category = db.StringProperty() 

追加と削除で順次モデルを更新することに関連するコストのため、モデルとはnum別にしました。したがって、私indexはアイテムの(非シーケンシャル)順序を維持するために使用し、特定のカテゴリのアイテムを表すdictのリストがデータストアから追い出されるたびに、それらを調べnumて各アイテムにシーケンシャル""を追加します。num私のUIは完全に動的であり(すべてAJAX、ページのリロードは一切ありません)、ブラウザーに送信されるすべてのアイテムをjavascriptでキャッシュするため、これは実際にはクライアント(読み取り:ブラウザー)専用です。サーバーサイド私は必ずしもアイテムの順番を並べる必要はありません。クライアント側にはそれを必要とする特定の関数があり、サーバーは非シーケンシャルインデックスで問題なく動作します。

私の質問の主な要点は、このモデルを保持する必要があるかどうか、つまり、カテゴリのすべてのアイテムをmemcacheに保存するか、データストアから直接アイテムを取得することに戻るかということになっているようです。アイテムはたくさん要求されます(正確な量や1秒間に何回の見積もりすらありませんが、1秒間に要求されるアイテムの数が多いはずです)。アイテムがキックアウトされる前にmemcacheにある時間を正確に決定する方法がないことは知っていますが、数分ごとに発生しないと想定できますか?それ以外の場合は、memcacheを使用するのが最善の方法だと思いますが、何かが足りない可能性があります。ああ、そしてうまくいけば、これがSOのディスクスペースをすべて盗む前の最後の編集になるでしょう;)

編集5これ以上の編集は必要ありません...これは、memcacheとデータストアまたはデータストアのみを使用した場合の時間計算量の計算のチャートです(データストアが何であるか正確にわからないため、データストアの時間計算量を省略しました。 BigTableのペーパーをもう一度読んで理解するのは遅すぎるので、ハッシュテーブルでの操作についても同じだと思います)。これらはすべて最良のケースです。memcacheソリューションの場合、最悪の場合、N個のデータストア読み取りを追加する必要があります(カテゴリ内のすべてのアイテムをmemcacheに読み取る必要があるため)。このグラフは、memcacheソリューションとデータストアソリューションの両方の方程式から、データの保存または取得(つまり、並べ替え、フィルター)とは関係のない余分なものを残しています。memcacheのみのソリューションの場合、numデータストアには保存されません。データストアのみのソリューションの場合はそうです。そのnumため、追加または削除(各アイテムの更新)に関連する追加コストが発生します。

n DS = number of DataStore operations
w = write
r = read
N = number of items in category (for Add and Remove this is the number before
    the operation is performed)
c = count of items to read
o = offset

+------------------------------------------------------------------------------+
|                  Memcache             |               Datastore              |
|------------------------------------------------------------------------------|
|       |                               |       |                              |
| Reads |           O(o + c)            | Reads |           c DS r             |
|-------+-------------------------------|-------+------------------------------| 
|       |                               |       |                              |
|Reads w|           O(o + c)            |Reads w|          o + c DS r          |
|Offset |                               |Offset |                              |
|-------+-------------------------------|-------+------------------------------|
|       |                               |       |                              |
| Adds  |         1 DS w + O(N)         | Adds  |   1 + N DS w & N - 1 DS r    |
|-------+-------------------------------|-------+------------------------------| 
|       |                               |       |                              |
|Removes|       1 DS rw + O(o + N)      |Removes|        N - o DS wr           |
|-------+-------------------------------|-------+------------------------------| 
|       |                               |       |                              |
| Edits |         1 DS rw + O(o)        | Edits |          1 DS rw             |
|-------+-------------------------------|-------+------------------------------|

したがって、問題は、memcacheソリューションの時間計算量がデータストアソリューションに伴う潜在的により多くのDS操作を上回るかどうかです。ただし、me​​mcacheエビクションがmemcacheソリューションでデータストアソリューションよりも多くのDS操作を引き起こす可能性がある場合を除きます(アイテムがmecacheから削除された場合N DS r、memcacheを再設定するために実行する必要があります)。これはすべて、最初のデータの読み込みが行われると、このアプリケーションでは書き込みよりも読み取りがはるかに頻繁に発生することを前提としています。

4

2 に答える 2

1

編集 4 を更新しました。

あなたのItemモデルは合理的に見えますが、最大の問題は、シーケンシャル インデックスをどのように管理するかです。データストアがデータの状態を適切にバックアップしていない限り、キャッシュの削除により読み取り操作(一般的でユーザー向け)が劇的に遅くなるため、私はあなたが説明した方法で memcache に依存することをまだためらっています。

そのため、引き続き memcache にアイテムを保存してください。ただし、挿入または削除時にnumは、データストアも更新してください。(memcache に のセット全体が既にある場合は、Items読み取り操作は必要ありません。memcache 内のすべてのアイテムを更新し、同時にデータストアに書き込むだけです。)

最悪のシナリオは、4 回目の編集の前に説明したとおりです。要素の挿入は、読み取り 1 回 + 書き込み 1 回です。要素の削除は、N 読み取り + N 書き込みであり、N はカテゴリ内のアイテムの数です。アイテムの検索は 1 回の読み取りで済みます。これらの各シナリオでは、memcache が空であることを前提としています。

オフセットを使用していた場合、各挿入は 1 回の書き込みになります。要素を削除すると、1 回の書き込みになります。ただし、要素の読み取りは N 回の読み取りであり、N は取得するアイテムのシーケンシャル インデックスです。memcache を使用しているが、データストアの値をバックアップしていない場合numも、このシナリオに陥ります。

ほとんどの場合、読み取りは書き込みよりもはるかに一般的であるためnum、データストアで維持する方がはるかに効率的です。

補遺:

データ サイズが大きすぎない場合は、Cloud SQL も別のオプションです。一般に、SQL は、実行しようとしているようなシーケンシャル クエリでははるかに優れていますが、大規模なデータ セットでのスケーリングが不十分になるという犠牲を払っています。

使用量が最小限であると思われる場合、使用ごとの価格は比較的安価です。

于 2012-07-12T04:32:36.453 に答える
-2

オフセットは、GAE でこれを行うための最良の方法です。クォータについて心配する必要はありません。オフセット後の読み取りのみをカウントします。つまり、最初の N 個のアイテムを読み取ると、オフセットから始まる N 個のアイテムを読み取るのと同じ量のクォータが消費されます。

于 2012-07-07T15:58:24.790 に答える