Skip to content

Commit

Permalink
Use array as NxN array to optimize search for relations.
Browse files Browse the repository at this point in the history
Drop relations when resetting clusters
  • Loading branch information
matiasdelellis committed Apr 24, 2020
1 parent db8a672 commit e726cff
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 24 deletions.
2 changes: 1 addition & 1 deletion lib/BackgroundJob/Tasks/CreateClustersTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ private function fillFaceRelationsFromPersons(string $userId, int $modelId): int
}

// Merge new suggested relations
return $this->relationMapper->merge($relations);
return $this->relationMapper->merge($userId, $modelId, $relations);
}

}
115 changes: 92 additions & 23 deletions lib/Db/RelationMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,25 @@ public function __construct(IDBConnection $db) {
parent::__construct($db, 'facerecog_relations', '\OCA\FaceRecognition\Db\Relation');
}

public function exists(Relation $relation): bool {
/**
* Find all relation from that user.
*
* @param string $userId User user to search
* @param int $modelId
* @return array
*/
public function findByUser(string $userId, int $modelId): array {
$qb = $this->db->getQueryBuilder();
$query = $qb
->select(['id'])
->from($this->getTableName())
->where($qb->expr()->andX($qb->expr()->eq('face1', $qb->createParameter('face1')), $qb->expr()->eq('face2', $qb->createParameter('face2'))))
->orWhere($qb->expr()->andX($qb->expr()->eq('face2', $qb->createParameter('face1')), $qb->expr()->eq('face1', $qb->createParameter('face2'))))
->setParameter('face1', $relation->getFace1())
->setParameter('face2', $relation->getFace2());

$resultStatement = $query->execute();
$row = $resultStatement->fetch();
$resultStatement->closeCursor();

return ($row !== false);
$qb->select('r.id', 'r.face1', 'r.face2', 'r.state')
->from($this->getTableName(), 'r')
->innerJoin('r', 'facerecog_faces', 'f', $qb->expr()->eq('r.face1', 'f.id'))
->innerJoin('f', 'facerecog_images', 'i', $qb->expr()->eq('f.image', 'i.id'))
->where($qb->expr()->eq('i.user', $qb->createParameter('user_id')))
->andWhere($qb->expr()->eq('i.model', $qb->createParameter('model_id')))
->setParameter('user_id', $userId)
->setParameter('model_id', $modelId);

return $this->findEntities($qb);
}

public function findFromPerson(string $userId, int $personId, int $state): array {
Expand Down Expand Up @@ -88,20 +92,85 @@ public function findFromPersons(int $personId1, int $personId2) {
return $this->findEntities($qb);
}

public function merge(array $relations): int {
$addedCount = 0;
/**
* Deletes all relations from that user.
*
* @param string $userId User to drop persons from a table.
*/
public function deleteUser(string $userId) {
$sub = $this->db->getQueryBuilder();
$sub->select(new Literal('1'))
->from('facerecog_faces', 'f')
->innerJoin('f', 'facerecog_images', 'i', $sub->expr()->eq('f.image', 'i.id'))
->andWhere($sub->expr()->eq('i.user', $sub->createParameter('user_id')));

$this->db->beginTransaction();
$qb = $this->db->getQueryBuilder();
$qb->delete($this->getTableName())
->where('EXISTS (' . $sub->getSQL() . ')')
->setParameter('user_id', $userId)
->execute();
}

/**
* Find all the relations of a user as an matrix array, which is faster to access.
* @param string $userId
* @param int $modelId
* return array
*/
public function findByUserAsMatrix(string $userId, int $modelId): array {
$matrix = array();
$relations = $this->findByUser($userId, $modelId);
foreach ($relations as $relation) {
if ($this->exists($relation))
continue;
$face1 = $relation->getFace1();
$face2 = $relation->getFace2();
$state = $relation->getState();

$row = array();
if (isset($matrix[$face1])) {
$row = $matrix[$face1];
}
$row[$face2] = $state;
$matrix[$face1] = $row;
}
return $matrix;
}

$this->insert($relation);
$addedCount++;
public function existsOnMatrix(Relation $relation, array $matrix): bool {
$face1 = $relation->getFace1();
$face2 = $relation->getFace2();

if (isset($matrix[$face1])) {
$row = $matrix[$face1];
if (isset($row[$face2])) {
return true;
}
}
if (isset($matrix[$face2])) {
$row = $matrix[$face2];
if (isset($row[$face1])) {
return true;
}
}
$this->db->commit();
return false;
}

return $addedCount;
public function merge(string $userId, int $modelId, array $relations): int {
$added = 0;
$this->db->beginTransaction();
try {
$oldMatrix = $this->findByUserAsMatrix($userId, $modelId);
foreach ($relations as $relation) {
if ($this->existsOnMatrix($relation, $oldMatrix))
continue;
$this->insert($relation);
$added++;
}
$this->db->commit();
} catch (\Exception $e) {
$this->db->rollBack();
throw $e;
}
return $added;
}

}
7 changes: 7 additions & 0 deletions lib/Service/FaceManagementService.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use OCA\FaceRecognition\Db\FaceMapper;
use OCA\FaceRecognition\Db\ImageMapper;
use OCA\FaceRecognition\Db\PersonMapper;
use OCA\FaceRecognition\Db\RelationMapper;

use OCA\FaceRecognition\Service\SettingsService;

Expand All @@ -56,19 +57,24 @@ class FaceManagementService {
/** @var PersonMapper */
private $personMapper;

/** @var RelationMapper */
private $relationMapper;

/** @var SettingsService */
private $settingsService;

public function __construct(IUserManager $userManager,
FaceMapper $faceMapper,
ImageMapper $imageMapper,
PersonMapper $personMapper,
RelationMapper $relationMapper,
SettingsService $settingsService)
{
$this->userManager = $userManager;
$this->faceMapper = $faceMapper;
$this->imageMapper = $imageMapper;
$this->personMapper = $personMapper;
$this->relationMapper = $relationMapper;
$this->settingsService = $settingsService;
}

Expand Down Expand Up @@ -134,6 +140,7 @@ public function resetClustersForUser(string $userId) {

$this->faceMapper->unsetPersonsRelationForUser($userId, $model);
$this->personMapper->deleteUserPersons($userId);
$this->relationMapper->deleteUser($userId);
}

/**
Expand Down

0 comments on commit e726cff

Please sign in to comment.