0

私のPython High Replication Datastoreアプリケーションでは、100,000〜1,000,000の大きなルックアップテーブルが必要です。私はそのコードに関連付けられた値を返すメソッドにコードを提供する必要があります(関連がない場合はNone)。たとえば、私のテーブルが受け入れ可能な英語の単語を保持していたら、単語が見つかった場合はTrueを返し、そうでない場合はFalse(またはNone)を返すようにします。GAEルックアップテーブルはトランザクションと互換性がありませんか?

私の現在の実装は、各テーブルエントリに対して1つの親なしエンティティを作成し、そのエンティティに関連するデータを格納することです。そのエンティティのデータストアキーをルックアップコードと同じに設定しました。 (キーの競合を防ぐために、すべてのエンティティを独自の名前空間に配置しますが、この質問には必須ではありません)。次に、コードでget_by_key_name()を呼び出して、関連するデータを取得します。

問題は、エンティティグループにまたがっているため、トランザクション中にこれらのエンティティにアクセスできないことです。そこで私の例に戻って、チャットセッションで使用されたすべての単語のスペルチェックをしたいとしましょう。私は彼らに共通の祖先を与えるので、私はチャットのすべてのメッセージにアクセスできましたが、そこには親がないので、私はワードテーブルにアクセスできませんでした。トランザクション中にテーブルを参照することが不可欠です。

私のルックアップテーブルは修正されているか、まれにしか変更されていません。これもスペルチェックの例と一致します。

1つの解決策は、1つのトランザクション中にチャットセッション内のすべての単語を読み込み、スペルチェック(結果の保存)して、保存された結果に対してスペルチェックを行う2回目のトランザクションを開始することです。しかし、これは非効率的であるだけでなく、チャットセッションがトランザクション間に追加された可能性があります。これは不器用な解決策のようです。

理想的には、ルックアップテーブルが不変であることをGAEに伝えたいと思います。このため、トランザクション内でエンティティグループをスパンすることについて不平を言わずにクエリを実行できるはずです。しかし、これを行う方法はありません。

memcacheにテーブルエントリを格納するのは魅力的ですが、それにも問題があります。大量のデータですが、GAEがmemcacheエントリを起動すると、トランザクション中にGAEが再ロードできなくなるという問題があります。

大きなグローバルルックアップテーブルの適切な実装について知っている人はいますか?

私はスペルチェックWebサービスなどを探しているわけではありません。私は、この質問を明確にするためだけに単語検索を例として使用しています。私は、大規模なルックアップテーブルのあらゆる種類の一般的な解決法を期待しています。

答えて

1

可能であれば、データをインスタンスメモリに挿入してください。インスタンスメモリに収まらない場合は、利用できるオプションがいくつかあります。

データがあまり変更されない場合は、アプリケーションでアップロードしたリソースファイルにデータを保存し、ディスクからアクセスすることができます。これは、簡単なディスク参照を可能にするデータ構造を構築できることを前提としています。実際には、独自の読み取り専用ディスクベースのテーブルを実装しています。

同様に、静的リソースとしては大きすぎる場合は、上記と同じアプローチを取ることができますが、データはblobstoreに格納します。

データが絶対にデータストアになければならない場合は、独自のリード・モディファイ・ライト・トランザクションをエミュレートする必要があります。あなたのレコードに 'revision'プロパティを追加してください。これを変更するには、レコードを(トランザクション外で)フェッチし、必要な変更を行い、トランザクション内で再度フェッチしてリビジョン値をチェックします。変更されていない場合は、独自のレコードのリビジョンをインクリメントし、データストアに格納します。

理論的には、複数の独立したトランザクション(および非トランザクション操作)をサポートしていますが、APIはトランザクション内からこれにアクセスする方法を現在公開していません。恐ろしい)ハック、残念なことに。

最後のオプション:メモリを増やしてプロビジョニングされたバックエンドを実行し、 'SpellCheckService'を公開し、フロントエンドからURLFetch呼び出しを行うことができます。インメモリはいつもどんなディスクベースのオプションよりもはるかに速くなることを覚えておいてください。

+0

+1をメモリに入れることを提案します。固定データの場合、これは最適である可能性が高い。 – SingleNegationElimination

+0

最初の提案に関しては、トランザクションを開始する前にテーブルをデータストアに保持してから、テーブル全体をインスタンスメモリに読み込むことが正しく理解できますか?それはうまくいくだろうが、テーブルは3MBのようなものを占めており、私はほんの一握りのテーブル参照しか必要としません。したがって、私が必要とするすべてが数百バイトであり、非効率的であると思うと、私は3MBで読んでいます。それとも他の何かを提案していますか?インスタンスメモリが(memcacheへの書き込みを除いて)リクエストに生き残る方法はありませんか? (そしてあなたの返事に感謝します - 日曜の夜はそれほどではありません!) – Dragonfly

+0

あなたの他のアイデアについては、私は "リビジョンプロパティ"のアイデアを理解しており、それと一緒に行くことができます。私はまだブロブストアやバックエンドについて学んでいないので、次にそれらを研究します。私はバックエンドを使うという音が好きです。その解決策には何らかの欠点がありますか? P.S.私はまだ、GAEをサポートすることで、トランザクションによってアクセスできる不変のデータストアエンティティをサポートすることをお勧めします。 – Dragonfly

1

まず、ネームスペースがキーの衝突を避けるために役立つと考えている場合は、もう一度足を戻してください。キーは、エンティティの種類、名前空間、名前またはID、およびエンティティが持つ可能性があるすべての親で構成されます。 2つの異なるエンティティの種類が同じ名前またはIDを持つことは完全に有効です。したがって、あなたが一致している、たとえばユニークな名前を指定して各メンバーを作成したLookupThingyがある場合、そのキーは他のものと衝突することはありません。

トランザクション内の育成されていないルックアップテーブルに対してスペルチェックと同等の処理を行う場合、ルックアップテーブルをコード内に保持することは可能ですか?

または、あなたが必要とするものに近いアナロジーを考えることができますか? 1つのトランザクション内でルックアップを行う必要性を促すもの?

+0

はい、別個の名前空間で保護が追加されないようにする必要があります。私はこれがキーの衝突を避けるかもしれないと考えていましたが、種類はデフォルトの名前空間内でさえも適切に行うべきです。 別の例:各郵便番号にデータを関連付けるとします。たとえば、平均所得数値やその他の人口統計があるとします。トランザクション内からこのテーブルをどのように参照することができますか?これは非常に一般的な問題のようです。 数百万のエントリがPythonコードに配線されていますか?私はそれがうまくいくと思うが、それは不合理に思われる。それが唯一の解決策ですか? – Dragonfly

+0

ルックアップテーブルとの照合をトランザクションで行う必要があるのはなぜですか?あなたはルックアップテーブルへのまれな変更から隔離しようとしていますか? –

+0

ここでは、トランザクションの必要性を完全に説明する余地はありませんが、ルックアップテーブルとは関係ありません。通常の理由です:私はエンティティグループに変更を加えており、データは原子的に扱われなければなりません。私はPythonですべてのテーブルデータを表現することを実験しましたが、これはコードに許されるスペースの量を超えました( "ソフトプロセスサイズの制限")。私はこれが期待されていたと思う。問題は未解決のままです。 – Dragonfly

関連する問題