Speed improvement for the "has common ancestor" filter rule. For a
database with 2300 persons the time to filter goes from 500 seconds to 80. I believe that the difference must be even bigger for larger database. The new algorithm is more or less linear. Each person is only visited once to compute the ancestors, and it does depth first. * src/Filters/Rules/Person/_HasCommonAncestorWith.py svn: r11451
This commit is contained in:
parent
13ad0f858e
commit
a2ea6b1e51
@ -49,35 +49,41 @@ class HasCommonAncestorWith(Rule):
|
||||
description = _("Matches people that have a common ancestor "
|
||||
"with a specified person")
|
||||
|
||||
def prepare(self,db):
|
||||
def prepare(self, db):
|
||||
self.db = db
|
||||
# Keys in `ancestor_cache' are ancestors of list[0].
|
||||
# We delay the computation of ancestor_cache until the
|
||||
# first use, because it's not uncommon to instantiate
|
||||
# this class and not use it.
|
||||
# For each(!) person we keep track of who their ancestors
|
||||
# are, in a set(). So we only have to compute a person's
|
||||
# ancestor list once.
|
||||
# Start with filling the cache for root person (gramps_id in self.list[0])
|
||||
self.ancestor_cache = {}
|
||||
self.root_person = db.get_person_from_gramps_id(self.list[0])
|
||||
self.add_ancs(db, self.root_person)
|
||||
|
||||
def add_ancs(self, db, person):
|
||||
if person.handle not in self.ancestor_cache:
|
||||
self.ancestor_cache[person.handle] = set()
|
||||
|
||||
for fam_handle in person.get_parent_family_handle_list():
|
||||
fam = db.get_family_from_handle(fam_handle)
|
||||
for par_handle in (fam.get_father_handle(), fam.get_mother_handle()):
|
||||
if par_handle:
|
||||
par = db.get_person_from_handle(par_handle)
|
||||
if par and par.handle not in self.ancestor_cache:
|
||||
self.add_ancs(db, par)
|
||||
if par:
|
||||
self.ancestor_cache[person.handle].add(par)
|
||||
self.ancestor_cache[person.handle] |= self.ancestor_cache[par.handle]
|
||||
|
||||
def reset(self):
|
||||
self.ancestor_cache = {}
|
||||
|
||||
def init_ancestor_cache(self,db):
|
||||
# list[0] is an Id, but we need to pass a Person to for_each_ancestor.
|
||||
try:
|
||||
handle = db.get_person_from_gramps_id(self.list[0]).get_handle()
|
||||
if handle:
|
||||
def init(self, handle): self.ancestor_cache[handle] = 1
|
||||
for_each_ancestor(db,[handle],init,self)
|
||||
except:
|
||||
pass
|
||||
def has_common_ancestor(self, other):
|
||||
if self.ancestor_cache[self.root_person.handle] & self.ancestor_cache[other.handle]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def apply(self,db,person):
|
||||
# On the first call, we build the ancestor cache for the
|
||||
# reference person. Then, for each person to test,
|
||||
# we browse his ancestors until we found one in the cache.
|
||||
if len(self.ancestor_cache) == 0:
|
||||
self.init_ancestor_cache(db)
|
||||
handle = person.handle
|
||||
return for_each_ancestor(
|
||||
db,[handle],
|
||||
lambda self, handle: handle in self.ancestor_cache,
|
||||
self);
|
||||
def apply(self, db, person):
|
||||
if person.handle not in self.ancestor_cache:
|
||||
self.add_ancs(db, person)
|
||||
|
||||
return self.has_common_ancestor(person)
|
||||
|
Loading…
Reference in New Issue
Block a user