5

多くのオブジェクト間の複雑な関係を格納するためにオブジェクトデータベース(ZODB)を使用していますが、パフォーマンスの問題が発生しています。その結果、オブジェクトの取得と挿入を高速化するためにインデックスの作成を開始しました。これが私の話です。あなたが助けてくれることを願っています。

最初にデータベースにオブジェクトを追加するときは、そのオブジェクトタイプ専用のブランチにオブジェクトを挿入します。同じエンティティを表す複数のオブジェクトを防ぐために、重複を見つけるためにブランチ内の既存のオブジェクトを反復処理するメソッドを追加しました。これは最初は機能しましたが、データベースのサイズが大きくなるにつれて、各オブジェクトをメモリにロードして属性をチェックするのにかかる時間が指数関数的に許容できないほど大きくなりました。

この問題を解決するために、オブジェクトの属性に基づいてインデックスを作成し始めました。これにより、オブジェクトが追加されたときに、タイプブランチと属性値インデックスブランチに保存されます。たとえば、firstName ='John'およびlastName='Smith'の属性を持つpersonオブジェクトを保存した場合、オブジェクトはpersonオブジェクトタイプブランチに追加され、キーを使用して属性インデックスブランチ内のリストにも追加されます。ジョン」と「スミス」。

これにより、新しいオブジェクトを分析でき、属性インデックス内で交差するオブジェクトのセットのみをチェックする必要があるため、重複チェックで多くの時間を節約できました。

しかし、オブジェクトを更新するときの処理に関して、すぐに別の問題に遭遇しました。インデックスは、もは​​や正確ではない可能性があるという事実を反映するように更新する必要があります。これには、古い値に直接アクセスしてオブジェクトを削除できるように記憶するか、オブジェクトを見つけて削除するために属性タイプのすべての値を反復処理する必要があります。いずれにせよ、パフォーマンスはすぐに再び低下し始めており、それを解決する方法を見つけることができません。

このような問題は以前に発生したことがありますか?あなたはそれを何で解決しましたか、それともこれはOODBMSを使用するときに私が対処しなければならないことですか?

助けてくれてありがとう。

4

2 に答える 2

8

はい、repoze.catalogは素晴らしく、十分に文書化されています。

つまり、インデックスをサイト構造の一部にしないでください。

  1. コンテナ/アイテム階層を使用してコンテンツアイテムオブジェクトを格納およびトラバースすることを検討してください。(a)パス(グラフのエッジがファイルシステムのように見える)または(b)特定の場所にあるシングルトンコンテナを識別することによってコンテンツをトラバースできるようにすることを計画します。

  2. RFC 4122 UUID(uuid.UUIDタイプ)または64ビット整数のいずれかを使用してコンテンツを識別します。

  3. 中央カタログを使用してインデックスを作成します(例:repoze.catalog)。カタログは、ZODBのルートアプリケーションオブジェクトに対して既知の場所にある必要があります。また、カタログはオブジェクトの属性にインデックスを付け、クエリでレコードID(通常は整数)を返す可能性があります。あなたの仕事は、それらの整数IDを(おそらくUUIDを介して)コンテンツを保存しているデータベース内の物理的なトラバーサルパスにマップすることです。ルート/アプリケーションから下に向かってオブジェクトグラフをトラバースするための一般的なインターフェイスにzope.locationとzope.containerを使用する場合に役立ちます。

  4. zope.lifecycleeventハンドラーを使用して、コンテンツにインデックスを付け、最新の状態に保ちます。

問題-一般化

ZODBは柔軟性が高すぎます。これは、トランザクションを含む永続的なオブジェクトグラフですが、これにより、独自のデータ構造やインターフェイスに没頭したり、泳いだりする余地があります。

解決策-一般化

通常、ZODB周辺のコミュニティから既存のイディオムを選択するだけで機能します:zope.lifecycleeventハンドラー、zope.containerとzope.locationを使用した「containerish」トラバーサル、およびrepoze.catalogなど。

より具体的に

一般化されたイディオムを使い果たして、それらが機能しない理由がわかっている場合にのみ、ZODBのさまざまなフレーバーのBTreeを使用して独自のインデックスを作成してみてください。私は実際に私が認めるよりも多くのことをしていますが、通常は正当な理由があります。

いずれの場合も、インデックス(検索、検出)とサイト(トラバーサルおよびストレージ)の構造を区別してください。

問題のあるドメインのイディオム

  • マスターZODBBTrees:おそらく必要なもの:

    • コンテンツオブジェクトをPersistentのサブクラスとして、コンテナインターフェイスを提供するOOBTreeのサブクラスであるコンテナに格納します(以下を参照)。
    • カタログまたはグローバルインデックスのBTreeを保存するか、repoze.catalogやzope.indexなどのパッケージを使用してその詳細を抽象化します(ヒント:カタログソリューションは通常、検索結果の整数レコードIDを生成するOIBTreeとしてインデックスを保存します。これらのレコードIDを、uuid(グラフをUUIDにトラバースできる場合)やパス(Zope2カタログのように)など、アプリケーションで解決可能なものに変換する一種のドキュメントマッパーユーティリティ。
  • IMHO、intidやkey-referencesなどを気にしないでください(これらは慣用的ではなく、必要がなければより困難です)。repoze.catalogのCatalogとDocumentMapを使用して、整数からuuidまたはパス形式の結果を取得し、オブジェクトを取得する方法を理解するだけです。検索から返されたIDまたはuuidを指定して、オブジェクトを取得する機能を持つユーティリティ/シングルトンが必要になる可能性があることに注意してください。

  • 同期イベントコールバック(ハンドラー)登録を提供するzope.lifecycleeventまたは同様のパッケージを使用します。これらのハンドラーは、オブジェクトに対してアトミック編集が行われるたびに呼び出す必要があります(トランザクションごとに1回の可能性がありますが、トランザクション機構では呼び出されません)。

  • Zopeコンポーネントアーキテクチャを学ぶ; 絶対的な要件ではありませんが、zope.containerのようなアップストリームパッケージのzope.interfaceインターフェースを理解するだけでも確かに役立ちます

  • Zope2(ZCatalog)がこれを行う方法の理解:複数のインデックスまたはさまざまな種類のカタログフロント。それぞれがクエリを検索し、それぞれが特殊なデータ構造を持ち、それぞれが整数レコードIDシーケンスを返します。これらは、設定された交差を実行するカタログによってインデックス間でマージされ、メタデータスタブを含む「brain」オブジェクトのレイジーマッピングとして返されます(各ブレインには、実際のコンテンツオブジェクトを取得するためのgetObject()メソッドがあります)。カタログ検索から実際のオブジェクトを取得するには、ルートアプリケーションオブジェクトからのパスを使用してカタログ化されたアイテムの場所を特定するというZope2イディオムに依存します。

于 2011-07-13T05:23:47.187 に答える
0

属性ハッシュ(JavaのhashCode()など)の使用を検討してから、32ビットのハッシュ値をキーとして使用します。Pythonにはハッシュ関数がありますが、私はそれについてあまり詳しくありません。

于 2011-07-12T18:05:46.787 に答える