Skip to content

Commit deaeefb

Browse files
committed
Fix for correct full rebuilding of search index.
Remove index directory after each test.
1 parent b1f6935 commit deaeefb

File tree

9 files changed

+130
-56
lines changed

9 files changed

+130
-56
lines changed

src/Nqxcode/LuceneSearch/Console/RebuildCommand.php

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Console\Command;
77
use Nqxcode\LuceneSearch\Locker\Locker;
88
use Nqxcode\LuceneSearch\Search;
9+
use Nqxcode\LuceneSearch\Support\SearchIndexRotator;
910
use Symfony\Component\Console\Helper\ProgressBar;
1011
use Symfony\Component\Console\Input\InputOption;
1112
use Symfony\Component\Console\Output\NullOutput;
@@ -21,6 +22,11 @@ class RebuildCommand extends Command
2122
*/
2223
private $search;
2324

25+
/**
26+
* @var SearchIndexRotator
27+
*/
28+
private $searchIndexRotator;
29+
2430
protected function getOptions()
2531
{
2632
return [
@@ -34,7 +40,7 @@ public function fire()
3440
$this->output = new NullOutput;
3541
}
3642

37-
$lockFilePath = sys_get_temp_dir() . '/laravel-lucene-search/rebuild.lock';
43+
$lockFilePath = storage_path('laravel-lucene-search/rebuild.lock');
3844

3945
$locker = new Locker($lockFilePath);
4046

@@ -44,10 +50,11 @@ public function fire()
4450

4551
$locker->doLocked(function () {
4652
if ($this->option('force')) {
47-
$this->forceRebuild();
53+
$this->call('search:clear');
54+
$this->rebuild();
4855

4956
} else {
50-
$this->softRebuild();
57+
$this->rebuild();
5158
}
5259
});
5360
}
@@ -57,6 +64,10 @@ private function rebuild()
5764
/** @var Search $search */
5865
$this->search = App::make('search');
5966

67+
$this->searchIndexRotator = App::make('search.index.rotator');
68+
$queue = Config::get('laravel-lucene-search::queue');
69+
$indexPath = Config::get('laravel-lucene-search::index.path');
70+
6071
$modelRepositories = $this->search->config()->repositories();
6172

6273
if (count($modelRepositories) > 0) {
@@ -74,19 +85,21 @@ private function rebuild()
7485
$progress = new ProgressBar($this->getOutput(), $count / $chunkCount);
7586
$progress->start();
7687

77-
$modelRepository->chunk($chunkCount, function ($chunk) use ($progress) {
78-
$queue = Config::get('laravel-lucene-search::queue');
88+
$modelRepository->chunk($chunkCount, function ($chunk) use ($progress, $queue) {
89+
$newIndexPath = $this->searchIndexRotator->getNewIndexPath();
90+
7991
if ($queue) {
8092
Queue::push(
8193
'Nqxcode\LuceneSearch\Job\MassUpdateSearchIndex',
8294
[
8395
'modelClass' => get_class($chunk[0]),
8496
'modelKeys' => $chunk->lists($chunk[0]->getKeyName()),
85-
'indexPath' => Config::get('laravel-lucene-search::index.path'),
97+
'indexPath' => $newIndexPath,
8698
],
8799
$queue);
88100

89101
} else {
102+
Config::set('laravel-lucene-search::index.path', $newIndexPath);
90103
foreach ($chunk as $model) {
91104
$this->search->update($model);
92105
}
@@ -102,30 +115,16 @@ private function rebuild()
102115
} else {
103116
$this->error('No models found in config.php file..');
104117
}
105-
}
106-
107-
private function softRebuild()
108-
{
109-
$oldIndexPath = Config::get('laravel-lucene-search::index.path');
110-
$newIndexPath = sys_get_temp_dir() . '/laravel-lucene-search/' . uniqid('index-', true);
111-
112-
Config::set('laravel-lucene-search::index.path', $newIndexPath);
113-
114-
$this->rebuild();
115118

116119
$this->search->destroyConnection();
117120

118-
File::cleanDirectory($oldIndexPath);
119-
File::copyDirectory($newIndexPath, $oldIndexPath);
120-
File::cleanDirectory($newIndexPath);
121+
if ($queue) {
122+
Queue::push('Nqxcode\LuceneSearch\Job\RotateSearchIndex', $queue);
121123

122-
Config::set('laravel-lucene-search::index.path', $oldIndexPath);
123-
124-
}
124+
} else {
125+
$this->searchIndexRotator->rotate();
126+
}
125127

126-
private function forceRebuild()
127-
{
128-
$this->call('search:clear');
129-
$this->rebuild();
128+
Config::set('laravel-lucene-search::index.path', $indexPath);
130129
}
131130
}

src/Nqxcode/LuceneSearch/Job/MassUpdateSearchIndex.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php namespace Nqxcode\LuceneSearch\Job;
22

33
use App\Models\CatalogProduct;
4+
use Config;
45

56
/**
67
* Class MassUpdateSearchIndex
@@ -13,10 +14,12 @@ public function fire($job, array $jobData)
1314
$modelKeys = $jobData['modelKeys'];
1415
$indexPath = $jobData['indexPath'];
1516

17+
Config::set('laravel-lucene-search::index.path', $indexPath);
18+
1619
foreach ($modelKeys as $modelKey) {
1720
$model = $modelClass::find($modelKey);
1821
if (!is_null($model)) {
19-
app('search')->useIndexPath($indexPath)->update($model);
22+
app('search')->update($model);
2023
}
2124
}
2225

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php namespace Nqxcode\LuceneSearch\Job;
2+
3+
use File;
4+
use Nqxcode\LuceneSearch\Support\SearchIndexRotator;
5+
6+
/**
7+
* Class RotateSearchIndex
8+
* @package Nqxcode\LuceneSearch\Job
9+
*/
10+
class RotateSearchIndex
11+
{
12+
public function fire($job, array $jobData)
13+
{
14+
app('search.index.rotator')->rotate();
15+
16+
$job->delete();
17+
}
18+
}

src/Nqxcode/LuceneSearch/Search.php

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ class Search
2828
*/
2929
protected $connection;
3030

31-
/**
32-
* @var string
33-
*/
34-
protected $indexPath;
35-
3631
/**
3732
* Get descriptor for open index.
3833
*
@@ -43,19 +38,6 @@ public function index()
4338
return $this->makeConnection()->getIndex();
4439
}
4540

46-
/**
47-
* Use index path for connection.
48-
*
49-
* @param $indexPath
50-
* @return $this
51-
*/
52-
public function useIndexPath($indexPath)
53-
{
54-
$this->indexPath = $indexPath;
55-
56-
return $this;
57-
}
58-
5941
/**
6042
* Model configurator.
6143
*
@@ -96,8 +78,8 @@ public function __destruct()
9678
*/
9779
private function makeConnection()
9880
{
99-
if (null === $this->connection) {
100-
$this->connection = call_user_func($this->connectionBuilder, $this->indexPath);
81+
if (!isset($this->connection)) {
82+
$this->connection = call_user_func($this->connectionBuilder);
10183
}
10284

10385
return $this->connection;

src/Nqxcode/LuceneSearch/ServiceProvider.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Nqxcode\LuceneSearch\Index\Connection;
77
use Nqxcode\LuceneSearch\Model\Config as ModelsConfig;
88
use Nqxcode\LuceneSearch\Model\SearchObserver;
9+
use Nqxcode\LuceneSearch\Support\SearchIndexRotator;
910
use ZendSearch\Lucene\Analysis\Analyzer\Common\Utf8Num\CaseInsensitive;
1011
use ZendSearch\Lucene\Search\QueryParser;
1112

@@ -51,9 +52,9 @@ public function register()
5152
QueryParser::setDefaultEncoding('utf-8');
5253

5354
return new Search(
54-
function ($indexPath = null) {
55+
function () {
5556
return new Connection(
56-
$indexPath ?: $this->app['search.index.path'],
57+
$this->app['search.index.path'],
5758
$this->app->make('Nqxcode\LuceneSearch\Analyzer\Config')
5859
);
5960
},
@@ -73,7 +74,7 @@ function ($indexPath = null) {
7374
);
7475
});
7576

76-
$this->app->bindShared('search.index.path', function () {
77+
$this->app->bind('search.index.path', function () {
7778
return Config::get('laravel-lucene-search::index.path');
7879
});
7980

@@ -85,6 +86,14 @@ function ($indexPath = null) {
8586
);
8687
});
8788

89+
$this->app->bindShared('search.index.rotator', function () {
90+
return new SearchIndexRotator(
91+
$this->app['search.index.path'],
92+
storage_path('laravel-lucene-search/index.new'),
93+
storage_path('laravel-lucene-search/index.preview')
94+
);
95+
});
96+
8897
$this->app->bindShared('command.search.rebuild', function () {
8998
return new Console\RebuildCommand;
9099
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php namespace Nqxcode\LuceneSearch\Support;
2+
3+
use File;
4+
5+
/**
6+
* Class SearchIndexRotator
7+
* @package Nqxcode\LuceneSearch\Support
8+
*/
9+
class SearchIndexRotator
10+
{
11+
private $currentIndexPath;
12+
private $newIndexPath;
13+
private $previewIndexPath;
14+
15+
public function __construct($currentPath, $newPath, $previewPath)
16+
{
17+
$this->currentIndexPath = $currentPath;
18+
$this->newIndexPath = $newPath;
19+
$this->previewIndexPath = $previewPath;
20+
}
21+
22+
/**
23+
* @return mixed
24+
*/
25+
public function getNewIndexPath()
26+
{
27+
return $this->newIndexPath;
28+
}
29+
30+
public function rotate()
31+
{
32+
File::deleteDirectory($this->previewIndexPath);
33+
34+
File::copyDirectory($this->currentIndexPath, $this->previewIndexPath);
35+
File::cleanDirectory($this->currentIndexPath);
36+
37+
File::copyDirectory($this->newIndexPath, $this->currentIndexPath);
38+
File::deleteDirectory($this->newIndexPath);
39+
}
40+
}

src/config/config.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323
'index' => [
2424

25-
'path' => storage_path() . '/lucene-search/index',
25+
'path' => storage_path('lucene-search/index'),
2626

2727
'models' => [
2828
// Add models descriptions here.

tests/functional/BaseTestCase.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php namespace tests\functional;
22

3+
use File;
34
use tests\TestCase;
45
use Config;
56

@@ -9,9 +10,12 @@
910
*/
1011
abstract class BaseTestCase extends TestCase
1112
{
13+
private $indexPath;
14+
1215
public function setUp()
1316
{
1417
parent::setUp();
18+
1519
$this->configure();
1620

1721
$artisan = $this->app->make('artisan');
@@ -23,10 +27,19 @@ public function setUp()
2327
$artisan->call('search:rebuild', ['--force' => true]);
2428
}
2529

30+
public function tearDown()
31+
{
32+
parent::tearDown();
33+
34+
app('search')->destroyConnection();
35+
36+
File::deleteDirectory($this->indexPath);
37+
}
38+
2639
protected function configure()
2740
{
28-
Config::set('laravel-lucene-search::index.path',
29-
sys_get_temp_dir() . '/laravel-lucene-search/index' . uniqid('index-', true));
41+
$this->indexPath = sys_get_temp_dir() . '/laravel-lucene-search/' . uniqid('index-', true);
42+
Config::set('laravel-lucene-search::index.path', $this->indexPath);
3043
Config::set(
3144
'laravel-lucene-search::index.models',
3245
[

tests/functional/Console/RebuildCommandTest.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<?php namespace tests\functional\Console;
22

3+
use Config;
4+
use File;
35
use Illuminate\Console\Application;
46
use Symfony\Component\Console\Output\BufferedOutput;
57
use tests\TestCase;
6-
use Config;
78

89
/**
910
* Class RebuildCommandTest
@@ -23,8 +24,17 @@ public function setUp()
2324
// Call migrations specific to our tests, e.g. to seed the db.
2425
$this->artisan->call('migrate', ['--database' => 'testbench', '--path' => '../tests/migrations']);
2526

26-
Config::set('laravel-lucene-search::index.path',
27-
sys_get_temp_dir() . '/laravel-lucene-search/index' . uniqid('index-', true));
27+
Config::set(
28+
'laravel-lucene-search::index.path',
29+
sys_get_temp_dir() . '/laravel-lucene-search/' . uniqid('index-', true)
30+
);
31+
}
32+
33+
public function tearDown()
34+
{
35+
parent::tearDown();
36+
37+
File::deleteDirectory(Config::get('laravel-lucene-search::index.path'));
2838
}
2939

3040
/**

0 commit comments

Comments
 (0)