From 9e0164f4f45cb68f9dccf96db28c8b05ed493be7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 8 Nov 2021 11:29:25 +0000 Subject: [PATCH] Further search system refactorings - Moved search term querying to its own method. - Updated Large content seeder to be more performant --- app/Entities/Tools/SearchIndex.php | 2 +- app/Entities/Tools/SearchRunner.php | 56 +++++++++++++++---------- database/seeders/LargeContentSeeder.php | 5 ++- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/app/Entities/Tools/SearchIndex.php b/app/Entities/Tools/SearchIndex.php index cc0b32d6a..541f06994 100644 --- a/app/Entities/Tools/SearchIndex.php +++ b/app/Entities/Tools/SearchIndex.php @@ -46,7 +46,7 @@ class SearchIndex * * @param Entity[] $entities */ - protected function indexEntities(array $entities) + public function indexEntities(array $entities) { $terms = []; foreach ($entities as $entity) { diff --git a/app/Entities/Tools/SearchRunner.php b/app/Entities/Tools/SearchRunner.php index dc54649be..6296c70e7 100644 --- a/app/Entities/Tools/SearchRunner.php +++ b/app/Entities/Tools/SearchRunner.php @@ -133,29 +133,14 @@ class SearchRunner protected function buildQuery(SearchOptions $searchOpts, string $entityType = 'page', string $action = 'view'): EloquentBuilder { $entity = $this->entityProvider->get($entityType); - $entitySelect = $entity->newQuery(); + $entityQuery = $entity->newQuery(); // Handle normal search terms - if (count($searchOpts->searches) > 0) { - $rawScoreSum = DB::raw('SUM(score) as score'); - $subQuery = DB::table('search_terms')->select('entity_id', 'entity_type', $rawScoreSum); - $subQuery->where('entity_type', '=', $entity->getMorphClass()); - $subQuery->where(function (Builder $query) use ($searchOpts) { - foreach ($searchOpts->searches as $inputTerm) { - $query->orWhere('term', 'like', $inputTerm . '%'); - } - })->groupBy('entity_type', 'entity_id'); - $entitySelect->join(DB::raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) { - $join->on('id', '=', 'entity_id'); - })->addSelect($entity->getTable() . '.*') - ->selectRaw('s.score') - ->orderBy('score', 'desc'); - $entitySelect->mergeBindings($subQuery); - } + $this->applyTermSearch($entityQuery, $searchOpts->searches, $entity); // Handle exact term matching foreach ($searchOpts->exacts as $inputTerm) { - $entitySelect->where(function (EloquentBuilder $query) use ($inputTerm, $entity) { + $entityQuery->where(function (EloquentBuilder $query) use ($inputTerm, $entity) { $query->where('name', 'like', '%' . $inputTerm . '%') ->orWhere($entity->textField, 'like', '%' . $inputTerm . '%'); }); @@ -163,18 +148,47 @@ class SearchRunner // Handle tag searches foreach ($searchOpts->tags as $inputTerm) { - $this->applyTagSearch($entitySelect, $inputTerm); + $this->applyTagSearch($entityQuery, $inputTerm); } // Handle filters foreach ($searchOpts->filters as $filterTerm => $filterValue) { $functionName = Str::camel('filter_' . $filterTerm); if (method_exists($this, $functionName)) { - $this->$functionName($entitySelect, $entity, $filterValue); + $this->$functionName($entityQuery, $entity, $filterValue); } } - return $this->permissionService->enforceEntityRestrictions($entity, $entitySelect, $action); + return $this->permissionService->enforceEntityRestrictions($entity, $entityQuery, $action); + } + + /** + * For the given search query, apply the queries for handling the regular search terms. + */ + protected function applyTermSearch(EloquentBuilder $entityQuery, array $terms, Entity $entity): void + { + if (count($terms) === 0) { + return; + } + + $subQuery = DB::table('search_terms')->select([ + 'entity_id', + 'entity_type', + DB::raw('SUM(score) as score'), + ]); + + $subQuery->where('entity_type', '=', $entity->getMorphClass()); + $subQuery->where(function (Builder $query) use ($terms) { + foreach ($terms as $inputTerm) { + $query->orWhere('term', 'like', $inputTerm . '%'); + } + })->groupBy('entity_type', 'entity_id'); + $entityQuery->join(DB::raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) { + $join->on('id', '=', 'entity_id'); + })->addSelect($entity->getTable() . '.*') + ->selectRaw('s.score') + ->orderBy('score', 'desc'); + $entityQuery->mergeBindings($subQuery); } /** diff --git a/database/seeders/LargeContentSeeder.php b/database/seeders/LargeContentSeeder.php index e8b6d74f6..dd9165978 100644 --- a/database/seeders/LargeContentSeeder.php +++ b/database/seeders/LargeContentSeeder.php @@ -33,8 +33,9 @@ class LargeContentSeeder extends Seeder $largeBook->pages()->saveMany($pages); $largeBook->chapters()->saveMany($chapters); + $all = array_merge([$largeBook], array_values($pages->all()), array_values($chapters->all())); - app()->make(PermissionService::class)->buildJointPermissions(); - app()->make(SearchIndex::class)->indexAllEntities(); + app()->make(PermissionService::class)->buildJointPermissionsForEntity($largeBook); + app()->make(SearchIndex::class)->indexEntities($all); } }