如果没有一个主节点或起始点,如何关联数据

2024-04-25 19:04:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一组包含身份号码的“人物”数据。这些数据来自如下格式的各种来源

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相关,这意味着所有这些身份都属于一个人,因此在三个实例中提供的数据,即DateOfBirth、MaritalStatus、HasPaidTax都属于一个人。你知道吗

目前,所有这些不同的idtype都放在一个表中:

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

问题是,如何在数据库中存储此ID号的相关性质?从我的搜索中,我发现了adjacency list model and nested set models。然而,这是为了存储层次信息。在我看来,没有什么是真正的父母或孩子的另一个。不是家谱。只是水平方向上相互关联的数字。没有一个ID类型是主ID

我正在使用python、postgresql和SQLAlchemy作为ORM,它有一些nested功能,尽管我仍然不确定这里的内容是否可以用层次结构表示。。。你知道吗


Tags: 数据id身份数字nestedv1t1p1
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
)

对于每一行,我抓取该行上的所有标识号,生成一个唯一的引用号,然后使用嵌套集模型,将相应的左值和右值设置为与标识相关的值。成功了。你知道吗

用嵌套集模型指出的唯一挑战是更新集是惩罚性的。在我的例子中,我需要检查每个idnumber是否已保存,获取保存时使用的id,对于后者,还需要检查保存时使用的idnumber,循环将一直持续到结束。。。。你知道吗

迭代完成后,我生成一个新的引用号并设置所有获取的id lft&rgt。查询成功了。但对于大约100万个与身份相关的条目,这个查询花了5天时间,但这仅仅是因为我在第5天杀死了它,到那时,它已经完成了大约70万个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,获取相关的引用号,然后对该引用号调用SQLdistinct搜索,以获取与该标识相关的不同的ID号。你知道吗

解决方案2:3行代码:NoSQL-Redis关键字:值集你知道吗

回到绘图板即谷歌。搜索“存储相关的识别号码”是的,我很绝望。。。我在instagram上找到了一篇文章Storing hundreds of millions of simple key-value pairs in Redis。假设Redis是我最好的新朋友,特别是因为我花了10分钟阅读简介,5分钟完成安装,40分钟完成3个基本教程。在那之后,我花了3个小时的时间真正解决了我的问题,而使用Redis,这基本上意味着试图找出最有效的方法来存储我的数据键:值对我的身份号码。现在我想我已经用4行代码解决了这个问题。你知道吗

在获取了一起提交的三个身份号码之后,我创建了一个名为relation的列表。使用Redis Sets,您不能有重复的值,因此即使我的三个标识号被多次提交,我的集合的长度也永远不会增长,我也不会像上面的关系数据库那样有重复的值。如果添加了额外的第4个ID,那么我的集合将增长1。重要的是,在相同的身份数下,这个代码花了2小时23分钟,总内存消耗为:“used\u memory\u peak\u 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)

我最好的新朋友。Redis。。。。你知道吗

我欢迎信息,以改善上述或一个全新的方式存储的关系。你知道吗

创建仅存储主键的第二个表Person

class Person(Base):
    id = Column(Integer, primary_key=True)
    idtentiy_numbers = relationship("IdentityNumber", backref="person")

class IdentityNumber(Base):
    ...
    person_id = Column(Integer, ForeignKey("person.id")

这里的基本思想是存储一个ID来分组。上面的一个是一个干净的解决方案,因为它还包含一个可用id的列表。您也可以在一个表中创建它,方法是不将person_id设为外键:这样它将只包含任意数字,例如1、2、3、。。。你知道吗

无论如何,您可以通过找出person_id是什么并按它分组来找出属于一起的数据。你知道吗

相关问题 更多 >