perform file search in a single query

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2021-05-05 19:36:41 +02:00
parent c3277095c7
commit e576d0da68
No known key found for this signature in database
GPG Key ID: 42B69D8A64526EFB
4 changed files with 31 additions and 60 deletions

View File

@ -803,7 +803,7 @@ class Cache implements ICache {
}
public function searchQuery(ISearchQuery $searchQuery) {
return $this->querySearchHelper->searchInCaches($searchQuery, [$this]);
return current($this->querySearchHelper->searchInCaches($searchQuery, [$this]));
}
/**

View File

@ -30,6 +30,7 @@ use OC\Files\Search\SearchBinaryOperator;
use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
@ -255,9 +256,10 @@ class QuerySearchHelper {
}
/**
* @template T of array-key
* @param ISearchQuery $searchQuery
* @param ICache[] $caches
* @return CacheEntry[]
* @param array<T, ICache> $caches
* @return array<T, ICacheEntry[]>
*/
public function searchInCaches(ISearchQuery $searchQuery, array $caches): array {
// search in multiple caches at once by creating one query in the following format
@ -298,9 +300,9 @@ class QuerySearchHelper {
$query->andWhere($searchExpr);
}
$storageFilters = array_map(function (ICache $cache) {
$storageFilters = array_values(array_map(function (ICache $cache) {
return $cache->getQueryFilterForStorage();
}, $caches);
}, $caches));
$query->andWhere($this->searchOperatorToDBExpr($builder, new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $storageFilters)));
if ($searchQuery->limitToHome() && ($this instanceof HomeCache)) {
@ -326,12 +328,12 @@ class QuerySearchHelper {
$result->closeCursor();
// loop trough all caches for each result to see if the result matches that storage
$results = [];
$results = array_fill_keys(array_keys($caches), []);
foreach ($rawEntries as $rawEntry) {
foreach ($caches as $cache) {
foreach ($caches as $cacheKey => $cache) {
$entry = $cache->getCacheEntryFromSearchResult($rawEntry);
if ($entry) {
$results[] = $entry;
$results[$cacheKey][] = $entry;
}
}
}

View File

@ -227,7 +227,7 @@ class CacheWrapper extends Cache {
}
public function searchQuery(ISearchQuery $searchQuery) {
return $this->querySearchHelper->searchInCaches($searchQuery, [$this]);
return current($this->querySearchHelper->searchInCaches($searchQuery, [$this]));
}
/**

View File

@ -31,6 +31,10 @@
namespace OC\Files\Node;
use OC\DB\QueryBuilder\Literal;
use OC\Files\Cache\QuerySearchHelper;
use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchOrder;
@ -253,69 +257,34 @@ class Folder extends Node implements \OCP\Files\Folder {
$mount = $this->root->getMount($this->path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($this->path);
$internalPath = rtrim($internalPath, '/');
if ($internalPath !== '') {
$internalPath = $internalPath . '/';
}
$subQueryLimit = $query->getLimit() > 0 ? $query->getLimit() + $query->getOffset() : 0;
$rootQuery = new SearchQuery(
new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'path', $internalPath . '%'),
$query->getSearchOperation(),
]),
$subQueryLimit,
0,
$query->getOrder(),
$query->getUser()
);
$files = [];
$cache = $storage->getCache('');
$results = $cache->searchQuery($rootQuery);
foreach ($results as $result) {
$files[] = $this->cacheEntryToFileInfo($mount, '', $internalPath, $result);
}
$caches = ['' => new CacheJail($storage->getCache(''), $internalPath)];
/** @var array{IMountPoint, string}[] $infoParams */
$infoParams = [
'' => [$mount, '']
];
if (!$limitToHome) {
$mounts = $this->root->getMountsIn($this->path);
foreach ($mounts as $mount) {
$subQuery = new SearchQuery(
$query->getSearchOperation(),
$subQueryLimit,
0,
$query->getOrder(),
$query->getUser()
);
$storage = $mount->getStorage();
if ($storage) {
$cache = $storage->getCache('');
$relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
$results = $cache->searchQuery($subQuery);
foreach ($results as $result) {
$files[] = $this->cacheEntryToFileInfo($mount, $relativeMountPoint, '', $result);
}
$caches[$relativeMountPoint] = $storage->getCache('');
$infoParams[$relativeMountPoint] = [$mount, ''];
}
}
}
$order = $query->getOrder();
if ($order) {
usort($files, function (FileInfo $a, FileInfo $b) use ($order) {
foreach ($order as $orderField) {
$cmp = $orderField->sortFileInfo($a, $b);
if ($cmp !== 0) {
return $cmp;
}
}
return 0;
});
}
$files = array_values(array_slice($files, $query->getOffset(), $query->getLimit() > 0 ? $query->getLimit() : null));
/** @var QuerySearchHelper $searchHelper */
$searchHelper = \OC::$server->get(QuerySearchHelper::class);
$resultsPerCache = $searchHelper->searchInCaches($query, $caches);
$files = array_merge(...array_map(function(array $results, $relativeMountPoint) use ($infoParams) {
$params = $infoParams[$relativeMountPoint];
return array_map(function(ICacheEntry $result) use ($relativeMountPoint, $params) {
return $this->cacheEntryToFileInfo($params[0], $relativeMountPoint, $params[1], $result);
}, $results);
}, array_values($resultsPerCache), array_keys($resultsPerCache)));
return array_map(function (FileInfo $file) {
return $this->createNode($file->getPath(), $file);