0

ID 番号を含む「人」データのセットがあります。このデータは、以下のような形式でさまざまなソースから取得されます

Source1: IDNumber:I1, Passport:P1,SocialSecurity:S1,DateOfBirth,13/03/1967
Source2: Passport:P1,VATNumber:V1,marital_status,Married
Source3: TaxNumber:T1,IDNumber:I1,HasPaidTax,True

同じ行に入力された数値は関連していることが前提です。したがって、上記のセットから、次の仮定を行うことができます。I1 は P1、S1、V1、T1 に関連しているということは、これらすべての ID が 1 人の人物に属していることを意味します。 HasPaidTax はすべて 1 人の個人に属します。

現在、このさまざまな IDType はすべて 1 つのテーブルにまとめられています。

PID=======IDTYpe=======IDNumber
 1---------IDNumber-----I1
 2---------Passport-----P1
 3---------VATNumber----V1
 etc

質問は、この ID 番号の関連性をデータベースに保存するにはどうすればよいですか? 私の検索から、私はadjacency list model と nested set modelsに出くわしました。ただし、これは階層情報を格納するためのものです。私の場合、実際には他の親または子ではありません。家系図ではありません。水平方向に互いに関連している数字だけです。ID タイプがマスター ID になることはありません

python、postgresql、および SQLAlchemy を ORM として使用しいますが、ここにあるものを階層的に表現できるかどうかはまだわかりません...

4

2 に答える 2

1

私はついに私の質問に役立つ解決策を得たと思います...ここでは、関係を2つの方法で保存する方法を示します。リレーショナル データベースでネストされたセット モデルを使用し、永続性を備えたキー値ベースのソリューションを使用する

解決策 1: ヘアコードを引っ張る: ネストされたセット モデル

CREATE TABLE identity
(
  id serial NOT NULL,
  identity_type_id integer NOT NULL,
  "number" character varying(50) NOT NULL,
  CONSTRAINT identity_pkey PRIMARY KEY (id),
  CONSTRAINT identity_identity_type_id_fkey FOREIGN KEY (identity_type_id)
      REFERENCES config_identity_type (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT identity_1 UNIQUE (identity_type_id, number)
)

CREATE TABLE identity_related
(
  id serial NOT NULL,
  identity_id integer NOT NULL,
  is_processed boolean NOT NULL DEFAULT false,
  ref_no character varying(20) NOT NULL,
  lft integer,
  rgt integer,
  CONSTRAINT identity_related_pkey PRIMARY KEY (id),
  CONSTRAINT identity_related_identity_id_fkey FOREIGN KEY (identity_id)
      REFERENCES identity (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

パースする行ごとに、その行のすべての ID 番号を取得し、一意の参照番号を生成してから、ネストされたセット モデルを使用して、それぞれの左右の値を identity_related に設定します。出来た。

ネストされたセット モデルで指摘される唯一の課題は、セットの更新が懲罰的であるということです。私の場合、各ID番号が保存されていることを確認し、保存されたIDを取得し、後で保存されたID番号も確認する必要があり、ループは最後まで続きます....

繰り返しが完了したら、新しい参照番号を生成し、取得したすべての ID を lft と rgt に設定します。クエリは機能しました。しかし、identity_related の約 100 万エントリの場合、このクエリには 5 日かかりましたが、それは 5 日目にそれを終了したためであり、それまでに約 700,000 の ID を処理していました。

コードは次のようになります。

def relate_identities(self, is_processed):
    #http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
    #http://www.sitepoint.com/hierarchical-data-database-2/
    #http://www.pure-performance.com/2009/03/managing-hierarchical-data-in-sql/
    #http://www.sqlalchemy.org/trac/browser/examples/nested_sets/nested_sets.py
    identify = Identity()
    session = Session()
    entries = []
    related = []
    tbl = IdentityRelated
    not_processed = False
    log_counter = 0
    id_counter = 0
    while True:
        #Get the initial record
        identity = session.query(tbl).filter(tbl.is_processed == is_processed).order_by(tbl.id).first()
        entries.append({identity:'not_processed'})
        related.append(identity)
        if len(entries) == 0: break
        #for key, value in entries[0].items():
            #print("ID:%s; ref_no:%s" %(key.id, key.ref_no))
        while True:
            for entry in entries:
                if not_processed == True: break
                for key, value in entry.items():
                    if value == 'not_processed':
                        not_processed = True
                        break
                    
            if not_processed == False: 
                break
            else:
                not_processed = False
            
            for entry in entries:
                for key, value in entry.items():
                    if value == 'not_processed': 
                        #Get objects which have the same identity_id as current object
                        duplicates = session.query(tbl).filter(tbl.identity_id == key.id).\
                                                            order_by(tbl.id).all()  
                        if len(duplicates) != 0: 
                            for duplicate in duplicates:
                                if not duplicate in related:
                                    related.append(duplicate)
                                    entries.append({duplicate:'not_processed'})
    
                        for entry in entries:
                            for key, value in entry.items():
                                if value == 'not_processed': 
                                    #Get objects that have the same reference numbers as all entries that we have fetched so far
                                    ref_nos = session.query(tbl).filter(tbl.ref_no == key.ref_no).order_by(tbl.id).all()
                                    for ref_no in ref_nos:
                                        if not ref_no in related:
                                            related.append(ref_no)
                                            entries.append({ref_no:'not_processed'})
                                    #Remove current entry from entries
                                    entries.remove(entry)
                                    #Add the entry but change the status
                                    entries.append({key:'processed'})
                    
        #Generate a new RelationCode
        while True:
            ref_no = get_reference_no(REFERENCE_NO.idrelation)
            params = {'key':'relation','relation':ref_no}
            if identify.get_identity(session, **params) == None:
                break             
        #Add each relatedID to the DB and set the Nested Set Value
        #Set is_processed as True to ensure we don't run it again
        relation_counter = 0
        for entry in entries:
            for key, value in entry.items():
                key.ref_no = ref_no
                key.lft = relation_counter + 1
                key.rgt = ((len(related) * 2) - relation_counter)
                key.is_processed = True
                relation_counter += 1  
    
        #Reset values
        log_counter += 1
        id_counter += 1
        related = []
        entries = []
            
        #Commit the session
        session.commit() 

このコードが最適化されて高速化されたとしても、関連する ID を照会するには、必要な ID を取得し、関連する参照番号distinctを取得してから、その参照番号に対して SQL 検索を呼び出して、その ID に関連する個別の ID 番号を取得する必要がありました。

解決策 2: 3 行のコード: NoSQL - Redis Key:Value Sets

製図板、つまり Google に戻ります。「関連する ID 番号の保存」の検索を行いました。ええ、私は絶望的でした...私は記事への Instagram エンジニアリングを得まし特に、イントロを読むのに 10 分、インストールを行うのに 5 分、3 つの基本的なチュートリアルを完了するのに 40 分かかったので、Redisが私の新しい親友だとしましょう。その後、実際に問題を解決するのに3時間かかりました. これで、4 行のコードでRedis Setsを使用して解決したと思います。

一緒に提出された 3 つの ID 番号を取得した後、relation というリストを作成します。RedisSetsでは、重複する値を持つことができないため、3 つの ID 番号が複数回送信されても​​、セットの長さは決して長くならず、上記の関係データベースで行ったように重複することはありません。追加の 4 番目の ID が追加されると、私のセットは 1 ずつ大きくなります。重要なのは、ID の数が同じ場合、このコードには 2 時間 23 分かかり、合計メモリ消費量は次のとおりです: 'used_memory_peak_human': '143.11M'

for related_outer in relation:
    #Create a set using the ID_Number as the key, and the other ID numbers as the values
    for related_inner in relation:
        redis_db.sadd(related_outer.number, related_inner.number)

私の新しい親友。レディス……

上記を改善するための情報、または関係を保存するまったく新しい方法を歓迎します。

于 2013-10-03T17:55:02.430 に答える