map: add migration
parent
72a08b917f
commit
1751ad7d80
|
@ -58,6 +58,7 @@ class MapController extends ApiBase
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$clusters = $this->timelineQuery->getMapClusters($gridLen, $bounds, $root);
|
$clusters = $this->timelineQuery->getMapClusters($gridLen, $bounds, $root);
|
||||||
|
|
||||||
return new JSONResponse($clusters);
|
return new JSONResponse($clusters);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
|
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
|
||||||
|
|
|
@ -44,7 +44,7 @@ trait TimelineQueryMap
|
||||||
$count = $query->createFunction('COUNT(m.fileid) AS count');
|
$count = $query->createFunction('COUNT(m.fileid) AS count');
|
||||||
|
|
||||||
$query->select($lat, $lon, $count)
|
$query->select($lat, $lon, $count)
|
||||||
->from('memories_map_clusters', 'c')
|
->from('memories_mapclusters', 'c')
|
||||||
;
|
;
|
||||||
|
|
||||||
if ($gridLen > 0.02) {
|
if ($gridLen > 0.02) {
|
||||||
|
@ -58,7 +58,7 @@ trait TimelineQueryMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// JOIN with memories for files from the current user
|
// JOIN with memories for files from the current user
|
||||||
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.map_cluster_id'));
|
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster'));
|
||||||
|
|
||||||
// JOIN with filecache for existing files
|
// JOIN with filecache for existing files
|
||||||
$query = $this->joinFilecache($query, $root, true, false);
|
$query = $this->joinFilecache($query, $root, true, false);
|
||||||
|
@ -96,7 +96,7 @@ trait TimelineQueryMap
|
||||||
|
|
||||||
// SELECT all photos with this tag
|
// SELECT all photos with this tag
|
||||||
$query->select('f.fileid', 'f.etag')->from('memories', 'm')->where(
|
$query->select('f.fileid', 'f.etag')->from('memories', 'm')->where(
|
||||||
$query->expr()->eq('m.map_cluster_id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT))
|
$query->expr()->eq('m.mapcluster', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT))
|
||||||
);
|
);
|
||||||
|
|
||||||
// WHERE these photos are in the user's requested folder recursively
|
// WHERE these photos are in the user's requested folder recursively
|
||||||
|
|
|
@ -15,6 +15,7 @@ use Psr\Log\LoggerInterface;
|
||||||
require_once __DIR__.'/../ExifFields.php';
|
require_once __DIR__.'/../ExifFields.php';
|
||||||
|
|
||||||
const DELETE_TABLES = ['memories', 'memories_livephoto', 'memories_places'];
|
const DELETE_TABLES = ['memories', 'memories_livephoto', 'memories_places'];
|
||||||
|
const TRUNCATE_TABLES = ['memories_mapclusters'];
|
||||||
|
|
||||||
class TimelineWrite
|
class TimelineWrite
|
||||||
{
|
{
|
||||||
|
@ -82,7 +83,7 @@ class TimelineWrite
|
||||||
|
|
||||||
// Check if need to update
|
// Check if need to update
|
||||||
$query = $this->connection->getQueryBuilder();
|
$query = $this->connection->getQueryBuilder();
|
||||||
$query->select('fileid', 'mtime', 'map_cluster_id')
|
$query->select('fileid', 'mtime', 'mapcluster')
|
||||||
->from('memories')
|
->from('memories')
|
||||||
->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
|
->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
|
||||||
;
|
;
|
||||||
|
@ -163,16 +164,24 @@ class TimelineWrite
|
||||||
// Store location data
|
// Store location data
|
||||||
$lat = null;
|
$lat = null;
|
||||||
$lon = null;
|
$lon = null;
|
||||||
$mapCluster = $prevRow ? (int) $prevRow['map_cluster_id'] : -1;
|
$mapCluster = $prevRow ? (int) $prevRow['mapcluster'] : -1;
|
||||||
if (\array_key_exists('GPSLatitude', $exif) && \array_key_exists('GPSLongitude', $exif)) {
|
if (\array_key_exists('GPSLatitude', $exif) && \array_key_exists('GPSLongitude', $exif)) {
|
||||||
try {
|
|
||||||
$lat = (float) $exif['GPSLatitude'];
|
$lat = (float) $exif['GPSLatitude'];
|
||||||
$lon = (float) $exif['GPSLongitude'];
|
$lon = (float) $exif['GPSLongitude'];
|
||||||
$mapCluster = $this->getMapCluster($fileId, $mapCluster, $lat, $lon);
|
|
||||||
|
try {
|
||||||
|
$mapCluster = $this->getMapCluster($mapCluster, $lat, $lon);
|
||||||
|
$mapCluster = $mapCluster <= 0 ? null : $mapCluster;
|
||||||
|
} catch (\Error $e) {
|
||||||
|
$logger = \OC::$server->get(LoggerInterface::class);
|
||||||
|
$logger->log(3, 'Error updating map cluster data: '.$e->getMessage(), ['app' => 'memories']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
$this->updatePlacesData($fileId, $lat, $lon);
|
$this->updatePlacesData($fileId, $lat, $lon);
|
||||||
} catch (\Error $e) {
|
} catch (\Error $e) {
|
||||||
$logger = \OC::$server->get(LoggerInterface::class);
|
$logger = \OC::$server->get(LoggerInterface::class);
|
||||||
$logger->log(3, 'Error updating geo data: '.$e->getMessage(), ['app' => 'memories']);
|
$logger->log(3, 'Error updating places data: '.$e->getMessage(), ['app' => 'memories']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +200,7 @@ class TimelineWrite
|
||||||
'liveid' => $query->createNamedParameter($liveid, IQueryBuilder::PARAM_STR),
|
'liveid' => $query->createNamedParameter($liveid, IQueryBuilder::PARAM_STR),
|
||||||
'lat' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
'lat' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
||||||
'lon' => $query->createNamedParameter($lon, IQueryBuilder::PARAM_STR),
|
'lon' => $query->createNamedParameter($lon, IQueryBuilder::PARAM_STR),
|
||||||
'map_cluster_id' => $query->createNamedParameter($mapCluster, IQueryBuilder::PARAM_INT),
|
'mapcluster' => $query->createNamedParameter($mapCluster, IQueryBuilder::PARAM_INT),
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($prevRow) {
|
if ($prevRow) {
|
||||||
|
@ -241,7 +250,7 @@ class TimelineWrite
|
||||||
public function clear()
|
public function clear()
|
||||||
{
|
{
|
||||||
$p = $this->connection->getDatabasePlatform();
|
$p = $this->connection->getDatabasePlatform();
|
||||||
foreach (DELETE_TABLES as $table) {
|
foreach (array_merge(DELETE_TABLES, TRUNCATE_TABLES) as $table) {
|
||||||
$this->connection->executeStatement($p->getTruncateTableSQL('*PREFIX*'.$table, false));
|
$this->connection->executeStatement($p->getTruncateTableSQL('*PREFIX*'.$table, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,27 +7,27 @@ namespace OCA\Memories\Db;
|
||||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
|
||||||
|
const CLUSTER_DEG = 0.0003;
|
||||||
|
|
||||||
trait TimelineWriteMap
|
trait TimelineWriteMap
|
||||||
{
|
{
|
||||||
protected IDBConnection $connection;
|
protected IDBConnection $connection;
|
||||||
|
|
||||||
protected function getMapCluster(int $fileId, int $prevCluster, float $lat, float $lon): int
|
protected function getMapCluster(int $prevCluster, float $lat, float $lon): int
|
||||||
{
|
{
|
||||||
// get all clusters within 30 metres
|
// Get all possible clusters within CLUSTER_DEG radius
|
||||||
$query = $this->connection->getQueryBuilder();
|
$query = $this->connection->getQueryBuilder();
|
||||||
$query->select('id')
|
$query->select('id', 'lat', 'lon')
|
||||||
->from('memories_map_clusters')
|
->from('memories_mapclusters')
|
||||||
->andWhere($query->expr()->gte('lat', $query->createNamedParameter($lat - 0.0003, IQueryBuilder::PARAM_STR)))
|
->andWhere($query->expr()->gte('lat', $query->createNamedParameter($lat - CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||||
->andWhere($query->expr()->lte('lat', $query->createNamedParameter($lat + 0.0003, IQueryBuilder::PARAM_STR)))
|
->andWhere($query->expr()->lte('lat', $query->createNamedParameter($lat + CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||||
->andWhere($query->expr()->gte('lon', $query->createNamedParameter($lon - 0.0003, IQueryBuilder::PARAM_STR)))
|
->andWhere($query->expr()->gte('lon', $query->createNamedParameter($lon - CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||||
->andWhere($query->expr()->lte('lon', $query->createNamedParameter($lon + 0.0003, IQueryBuilder::PARAM_STR)))
|
->andWhere($query->expr()->lte('lon', $query->createNamedParameter($lon + CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||||
;
|
;
|
||||||
|
$rows = $query->executeQuery()->fetchAll();
|
||||||
$result = $query->executeQuery();
|
|
||||||
$rows = $result->fetchAll();
|
|
||||||
|
|
||||||
// Find cluster closest to the point
|
// Find cluster closest to the point
|
||||||
$minDist = 999999999;
|
$minDist = PHP_INT_MAX;
|
||||||
$minId = -1;
|
$minId = -1;
|
||||||
foreach ($rows as $r) {
|
foreach ($rows as $r) {
|
||||||
$clusterLat = (float) $r['lat'];
|
$clusterLat = (float) $r['lat'];
|
||||||
|
@ -59,10 +59,28 @@ trait TimelineWriteMap
|
||||||
return $minId;
|
return $minId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createMapCluster(float $lat, float $lon): int
|
protected function addToCluster(int $clusterId, float $lat, float $lon): void
|
||||||
|
{
|
||||||
|
if ($clusterId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->connection->getQueryBuilder();
|
||||||
|
$query->update('memories_mapclusters')
|
||||||
|
->set('point_count', $query->createFunction('point_count + 1'))
|
||||||
|
->set('lat_sum', $query->createFunction("lat_sum + {$lat}"))
|
||||||
|
->set('lon_sum', $query->createFunction("lon_sum + {$lon}"))
|
||||||
|
->set('lat', $query->createFunction('lat_sum / point_count'))
|
||||||
|
->set('lon', $query->createFunction('lon_sum / point_count'))
|
||||||
|
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
||||||
|
;
|
||||||
|
$query->executeStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMapCluster(float $lat, float $lon): int
|
||||||
{
|
{
|
||||||
$query = $this->connection->getQueryBuilder();
|
$query = $this->connection->getQueryBuilder();
|
||||||
$query->insert('memories_map_clusters')
|
$query->insert('memories_mapclusters')
|
||||||
->values([
|
->values([
|
||||||
'point_count' => $query->createNamedParameter(1, IQueryBuilder::PARAM_INT),
|
'point_count' => $query->createNamedParameter(1, IQueryBuilder::PARAM_INT),
|
||||||
'lat_sum' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
'lat_sum' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
||||||
|
@ -76,35 +94,17 @@ trait TimelineWriteMap
|
||||||
return (int) $query->getLastInsertId();
|
return (int) $query->getLastInsertId();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function removeFromCluster(int $clusterId, float $lat, float $lon): void
|
private function removeFromCluster(int $clusterId, float $lat, float $lon): void
|
||||||
{
|
{
|
||||||
if ($clusterId <= 0) {
|
if ($clusterId <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->connection->getQueryBuilder();
|
$query = $this->connection->getQueryBuilder();
|
||||||
$query->update('memories_map_clusters')
|
$query->update('memories_mapclusters')
|
||||||
->set('point_count', $query->createFunction('point_count - 1'))
|
->set('point_count', $query->createFunction('point_count - 1'))
|
||||||
->set('lat_sum', $query->createFunction('lat_sum - '.$lat))
|
->set('lat_sum', $query->createFunction("lat_sum - {$lat}"))
|
||||||
->set('lon_sum', $query->createFunction('lon_sum - '.$lon))
|
->set('lon_sum', $query->createFunction("lon_sum - {$lon}"))
|
||||||
->set('lat', $query->createFunction('lat_sum / point_count'))
|
|
||||||
->set('lon', $query->createFunction('lon_sum / point_count'))
|
|
||||||
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
|
||||||
;
|
|
||||||
$query->executeStatement();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function addToCluster(int $clusterId, float $lat, float $lon): void
|
|
||||||
{
|
|
||||||
if ($clusterId <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = $this->connection->getQueryBuilder();
|
|
||||||
$query->update('memories_map_clusters')
|
|
||||||
->set('point_count', $query->createFunction('point_count + 1'))
|
|
||||||
->set('lat_sum', $query->createFunction('lat_sum + '.$lat))
|
|
||||||
->set('lon_sum', $query->createFunction('lon_sum + '.$lon))
|
|
||||||
->set('lat', $query->createFunction('lat_sum / point_count'))
|
->set('lat', $query->createFunction('lat_sum / point_count'))
|
||||||
->set('lon', $query->createFunction('lon_sum / point_count'))
|
->set('lon', $query->createFunction('lon_sum / point_count'))
|
||||||
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
||||||
|
|
|
@ -48,8 +48,8 @@ class Version401100Date20230208181533 extends SimpleMigrationStep
|
||||||
/** @var ISchemaWrapper $schema */
|
/** @var ISchemaWrapper $schema */
|
||||||
$schema = $schemaClosure();
|
$schema = $schemaClosure();
|
||||||
|
|
||||||
|
// Add lat lon to memories
|
||||||
$table = $schema->getTable('memories');
|
$table = $schema->getTable('memories');
|
||||||
|
|
||||||
if (!$table->hasColumn('lat')) {
|
if (!$table->hasColumn('lat')) {
|
||||||
$table->addColumn('lat', Types::DECIMAL, [
|
$table->addColumn('lat', Types::DECIMAL, [
|
||||||
'notnull' => false,
|
'notnull' => false,
|
||||||
|
@ -63,8 +63,44 @@ class Version401100Date20230208181533 extends SimpleMigrationStep
|
||||||
'precision' => 9,
|
'precision' => 9,
|
||||||
'scale' => 6,
|
'scale' => 6,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$table->addIndex(['lat', 'lon'], 'memories_lat_lon_index');
|
$table->addIndex(['lat', 'lon'], 'memories_lat_lon_index');
|
||||||
|
|
||||||
|
$table->addColumn('mapcluster', Types::INTEGER, [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => null,
|
||||||
|
]);
|
||||||
|
$table->addIndex(['mapcluster'], 'memories_mapcluster_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add clusters table
|
||||||
|
if (!$schema->hasTable('memories_mapclusters')) {
|
||||||
|
$table = $schema->createTable('memories_mapclusters');
|
||||||
|
$table->addColumn('id', Types::INTEGER, [
|
||||||
|
'autoincrement' => true,
|
||||||
|
'notnull' => true,
|
||||||
|
]);
|
||||||
|
$table->addColumn('point_count', Types::INTEGER, [
|
||||||
|
'notnull' => true,
|
||||||
|
]);
|
||||||
|
$table->addColumn('lat_sum', Types::FLOAT, [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => null,
|
||||||
|
]);
|
||||||
|
$table->addColumn('lon_sum', Types::FLOAT, [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => null,
|
||||||
|
]);
|
||||||
|
$table->addColumn('lat', Types::FLOAT, [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => null,
|
||||||
|
]);
|
||||||
|
$table->addColumn('lon', Types::FLOAT, [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table->setPrimaryKey(['id']);
|
||||||
|
$table->addIndex(['lat', 'lon'], 'memories_clst_ll_idx');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $schema;
|
return $schema;
|
||||||
|
|
Loading…
Reference in New Issue