web-dev-qa-db-ja.com

並列ライブラリの維持:バイナリファイルアクセス+メタデータデータベースORM設計

私はいくつかの入力に感謝するより高いレベルのデータ抽象化を扱っています。

大規模なデータレイクを使用するアプリケーションに取り組んでいます。データレイクは、数千の大きなバイナリファイル(それぞれ250 MB以上から最大数GB)で構成され、各ファイルには、ファイルを一意に識別する非常に少量のメタデータ(数kB)が含まれています。バイナリファイルには最終的に目的のデータが含まれますが、特定のユーザーのクエリに役立つのはバイナリファイルのサブセットのみです。バイナリファイルの「レジストリ」のような役割を果たすデータベースを作成しました。 ORMマッピングを作成してメタデータを効果的かつ効率的にナビゲートして、特定のクエリが実際にロードする必要があるバイナリファイルを特定するクエリに役立つバイナリファイルを決定しました。このライブラリのユーザーには書き込みアクセス権がなく、読み取りアクセス権がないことを知っておくことが重要な場合があります。

設計の問題は、データにアクセスするための2つの並列ライブラリ、バイナリファイル内のデータ(メタデータを含む)のクラスのセット、およびすべてのメタデータのORMクラスを維持しているという事実から生じます。これらのクラスのかなりの数は、お互いのほぼカーボンコピーです。これらのライブラリを組み合わせて、メタデータオブジェクトを常にormエンティティにすることは理にかなっていますか?データベースへのアクセスを必要とせずにバイナリファイルをロードできるようにしたいことに注意してください。これは大幅な変更であるため、これを行うことをためらっていますが、コードのメンテナンスの観点からは、本当にクリーンアップされます。

必要に応じて、ORMのpythonでsqlalchemyを使用します。

編集:これは、コードベースの現在の状態の簡略化された例です(これが雑草の中にある場合は申し訳ありません)。

current.py

class BinaryMetadata:
    """Represents the metadata of each binary file. A few kB."""

    def __init__(*args, **kwargs)
        self.field_0 =  # ... save a few kB of
                        #
                        # ... metadata attributes
                        #
        self.field_n =  # ... in this file.


class BinaryFile:
    """A handler to read any part 1GB+ binary file, both 
    metadata and any data not in the database."""

    @classmethod
    def fromfilepath(cls, fp):
        """Load a file from disk"""
        with open(fp, 'rb') as file:
            args1 = # .... read metadata.
            args2 = # .... and any other data
        return cls(fp, BinaryMetadata(*args1), *args2)

    def __init__(self, fp, metadata, *args, **kwargs)
        self.filepath = filepath
        self.metadata = metadata # Instance of `BinaryMetadata`

    def read_binary_data(self, *args):
        # ...load 1GB+ of data binary file (not stored in ORM)...
        return binary_data

ORMBase =  #... base class for ORM


class ORMMetadata(ORMBase):
    """Mapping of table of full of data `BinaryMetatadata`"""

    id =  # ...
    field_0 =   # ... save the same  
                #
                # ... attributes here 
                #
    field_n =   # ... as in `BinaryMetadata`

問題は、BinaryMetadataORMMetadataが格納するデータの点でほぼ同じことであり、ORMMetadataは両方の場所にあります。これは、APIユーザーがデータベースAPIを使用することを強制するようなものですが、メタデータクラスをマージして両方の場所で1つだけを使用できれば、ほぼ同じクラスORMMetadataBinaryMetadata

4
user27886

一歩下がってください。

2つのAPIの間に共通点がある場合、それらは同じことについて議論しています。

その同一性を、シリアライゼーションAPIおよびデータベースAPIによって拡張されるライブラリに抽出できます。

これは、これらの一般的なアイデアを明確にするのに役立ちます。また、すでに2つの例があるので、それらのアイデアがどのように拡張されるかについても説明します。

共有構造が剛性を生み出す

同じものを抽出することの唯一の欠点は、柔軟性が大幅に低下する可能性があることです。剛性が適切な場所にある場合、これはミスを回避するのに役立ちますが、剛性が間違った場所にある場合、いくつかの深刻な問題が発生する可能性があります。

  • どちらのAPIも共有ライブラリに依存しているため、そのライブラリへの変更は両方の表現に影響します
  • 両方のAPIは、この共有ライブラリを、ダウンストリームコンシューマーへのインターフェースの一部として公開します。これにより、ユーザーの好みに関係なく、ライブラリがインポートされます。
  • コンシューマーが両方のAPIを使用しているが、それらのAPIが同じバージョンの共有ライブラリを使用していない場合、問題が発生します。技術的な拘束力の問題は小魚であり、意味上の問題はさらに悪化します。

遠近法

両方のAPIがこの共通のオブジェクトモデルを作成して操作する必要があるため、適切な方法で柔軟にすることは困難です。おそらく、視点を変えることで問題を明確にすることができます。

これを2つの重複するAPIと見なす代わりに、2つの化身を持つ単一のAPIと見なします。

  • 1つの化身は、データベース指向であり、インデックスなどを活用しています...
  • 1つは、バイナリシリアル化形式を利用するフラットファイル指向です。

この観点から、ERMとフラットファイルは、ある種のプロバイダーインターフェイスの背後に隠されている可能性がある実装の詳細であることが正しくわかります。

この意味で、これらは単一のAPIのプラグインになります。

  • コンシューマは、プラグインをロードせず、オブジェクト構造自体にアクセスすることを選択できます。
  • コンシューマは、どちらか一方または両方のプラグインをロードして、ファイルまたは湖に保存されているデータにアクセスすることを選択できます。
  • テストは、迅速なテストを可能にするメモリ内プラグインを提供できます。
  • APIを更新して、下位互換性のある方法で新機能を提供できます。
  • プラグインは、下位互換性のある方法で実行できるように更新できます。
4
Kain0_0