Skip to content

Commit 747f035

Browse files
bors[bot]mkilmanas
andauthored
Merge #242
242: Make import command resumabe r=brunoocasali a=mkilmanas # Pull Request Make it possible to resume import from a mid-point after unsuccessful previous import ## Related issue Fixes #241 ## What does this PR do? - Makes import resumable: - Introduce `--skip-batches` parameter - Enforce entity sorting by primary key (consistent, fast) - Display the number of processed entities - Add test case - Other small improvements: - Clarify wording of the message telling the number of indexed records - Update existing tests for modified messages ## PR checklist Please check if your PR fulfills the following requirements: - [x] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)? - [x] Have you read the contributing guidelines? - [x] Have you made sure that the title is accurate and descriptive of the changes? Co-authored-by: Marijus Kilmanas <[email protected]>
2 parents bb21947 + aa11283 commit 747f035

File tree

3 files changed

+80
-32
lines changed

3 files changed

+80
-32
lines changed

src/Command/MeilisearchImportCommand.php

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ protected function configure(): void
5555
'Update settings related to indices to the search engine'
5656
)
5757
->addOption('batch-size', null, InputOption::VALUE_REQUIRED)
58+
->addOption(
59+
'skip-batches',
60+
null,
61+
InputOption::VALUE_REQUIRED,
62+
'Skip the first N batches and start importing from the N+1 batch',
63+
0
64+
)
5865
->addOption(
5966
'response-timeout',
6067
't',
@@ -86,7 +93,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8693
}
8794

8895
$entitiesToIndex = array_unique($indexes->all(), SORT_REGULAR);
89-
$batchSize = $input->getOption('batch-size');
96+
$batchSize = $input->getOption('batch-size') ?? '';
9097
$batchSize = ctype_digit($batchSize) ? (int) $batchSize : $config->get('batchSize');
9198
$responseTimeout = ((int) $input->getOption('response-timeout')) ?: self::DEFAULT_RESPONSE_TIMEOUT;
9299

@@ -97,29 +104,47 @@ protected function execute(InputInterface $input, OutputInterface $output): int
97104
continue;
98105
}
99106

107+
$totalIndexed = 0;
108+
100109
$manager = $this->managerRegistry->getManagerForClass($entityClassName);
101110
$repository = $manager->getRepository($entityClassName);
111+
$classMetadata = $manager->getClassMetadata($entityClassName);
112+
$entityIdentifiers = $classMetadata->getIdentifierFieldNames();
113+
$sortByIdentifiersParam = array_combine($entityIdentifiers, array_fill(0, count($entityIdentifiers), 'ASC'));
102114

103115
$output->writeln('<info>Importing for index '.$entityClassName.'</info>');
104116

105-
$page = 0;
117+
$page = max(0, (int) $input->getOption('skip-batches'));
118+
119+
if ($page > 0) {
120+
$output->writeln(
121+
sprintf(
122+
'<info>Skipping first <comment>%d</comment> batches (<comment>%d</comment> records)</info>',
123+
$page,
124+
$page * $batchSize,
125+
)
126+
);
127+
}
128+
106129
do {
107130
$entities = $repository->findBy(
108131
[],
109-
null,
132+
$sortByIdentifiersParam,
110133
$batchSize,
111134
$batchSize * $page
112135
);
113136

114137
$responses = $this->formatIndexingResponse($this->searchService->index($manager, $entities), $responseTimeout);
138+
$totalIndexed += count($entities);
115139
foreach ($responses as $indexName => $numberOfRecords) {
116140
$output->writeln(
117141
sprintf(
118-
'Indexed <comment>%s / %s</comment> %s entities into %s index',
142+
'Indexed a batch of <comment>%d / %d</comment> %s entities into %s index (%d indexed since start)',
119143
$numberOfRecords,
120144
count($entities),
121145
$entityClassName,
122-
'<info>'.$indexName.'</info>'
146+
'<info>'.$indexName.'</info>',
147+
$totalIndexed,
123148
)
124149
);
125150
}

tests/Integration/CommandsTest.php

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,25 @@ public function testSearchImportAndClearAndDeleteWithoutIndices(): void
7474

7575
$this->assertSame(<<<'EOD'
7676
Importing for index Meilisearch\Bundle\Tests\Entity\Post
77-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index
78-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index
77+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index (6 indexed since start)
78+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index (6 indexed since start)
7979
Settings updated.
8080
Settings updated.
8181
Settings updated.
8282
Importing for index Meilisearch\Bundle\Tests\Entity\Comment
8383
Importing for index Meilisearch\Bundle\Tests\Entity\Tag
84-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index
85-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__aggregated index
84+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index (6 indexed since start)
85+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__aggregated index (6 indexed since start)
8686
Importing for index Meilisearch\Bundle\Tests\Entity\Link
8787
Importing for index Meilisearch\Bundle\Tests\Entity\Page
88-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
88+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (6 indexed since start)
8989
Importing for index Meilisearch\Bundle\Tests\Entity\SelfNormalizable
9090
Importing for index Meilisearch\Bundle\Tests\Entity\Post
91-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index
92-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index
91+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index (6 indexed since start)
92+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__aggregated index (6 indexed since start)
9393
Importing for index Meilisearch\Bundle\Tests\Entity\Tag
94-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index
95-
Indexed 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__aggregated index
94+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index (6 indexed since start)
95+
Indexed a batch of 6 / 6 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__aggregated index (6 indexed since start)
9696
Done!
9797

9898
EOD, $importOutput);
@@ -150,12 +150,12 @@ public function testSearchImportWithCustomBatchSize(): void
150150

151151
$this->assertSame(<<<'EOD'
152152
Importing for index Meilisearch\Bundle\Tests\Entity\Page
153-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
154-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
155-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
156-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
157-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
158-
Indexed 1 / 1 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index
153+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (2 indexed since start)
154+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (4 indexed since start)
155+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (6 indexed since start)
156+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (8 indexed since start)
157+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (10 indexed since start)
158+
Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (11 indexed since start)
159159
Done!
160160

161161
EOD, $importOutput);
@@ -176,7 +176,7 @@ public function testSearchImportWithCustomResponseTimeout(): void
176176
$output = $importCommandTester->getDisplay();
177177

178178
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Page', $output);
179-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index', $output);
179+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index ('.$i.' indexed since start)', $output);
180180
$this->assertStringContainsString('Done!', $output);
181181
$this->assertSame(0, $return);
182182

@@ -197,7 +197,7 @@ public function testSearchImportWithCustomResponseTimeout(): void
197197
$output = $importCommandTester->getDisplay();
198198

199199
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Page', $output);
200-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index', $output);
200+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index ('.$i.' indexed since start)', $output);
201201
$this->assertStringContainsString('Done!', $output);
202202
$this->assertSame(0, $return);
203203
}
@@ -221,8 +221,8 @@ public function testImportDifferentEntitiesIntoSameIndex(): void
221221

222222
$output = $commandTester->getDisplay();
223223
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Tag', $output);
224-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index', $output);
225-
$this->assertStringContainsString('Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\Link entities into sf_phpunit__tags index', $output);
224+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index ('.$i.' indexed since start)', $output);
225+
$this->assertStringContainsString('Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\Link entities into sf_phpunit__tags index (2 indexed since start)', $output);
226226
$this->assertStringContainsString('Done!', $output);
227227

228228
/** @var SearchResult $searchResult */
@@ -245,7 +245,30 @@ public function testSearchImportAggregator(): void
245245

246246
$output = $commandTester->getDisplay();
247247
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Post', $output);
248-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index', $output);
248+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index ('.$i.' indexed since start)', $output);
249+
$this->assertStringContainsString('Done!', $output);
250+
$this->assertSame(0, $return);
251+
}
252+
253+
public function testSearchImportWithSkipBatches(): void
254+
{
255+
for ($i = 0; $i < 10; ++$i) {
256+
$this->createPage($i);
257+
}
258+
259+
$command = $this->application->find('meili:import');
260+
$commandTester = new CommandTester($command);
261+
$return = $commandTester->execute([
262+
'--indices' => 'pages',
263+
'--batch-size' => '3',
264+
'--skip-batches' => '2',
265+
]);
266+
267+
$output = $commandTester->getDisplay();
268+
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Page', $output);
269+
$this->assertStringContainsString('Skipping first 2 batches (6 records)', $output);
270+
$this->assertStringContainsString('Indexed a batch of 3 / 3 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (3 indexed since start)', $output);
271+
$this->assertStringContainsString('Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\Page entities into sf_phpunit__pages index (4 indexed since start)', $output);
249272
$this->assertStringContainsString('Done!', $output);
250273
$this->assertSame(0, $return);
251274
}
@@ -264,7 +287,7 @@ public function testImportingIndexNameWithAndWithoutPrefix(): void
264287

265288
$output = $commandTester->getDisplay();
266289
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Post', $output);
267-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index', $output);
290+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index ('.$i.' indexed since start)', $output);
268291
$this->assertStringContainsString('Done!', $output);
269292
$this->assertSame(0, $return);
270293

@@ -283,7 +306,7 @@ public function testImportingIndexNameWithAndWithoutPrefix(): void
283306

284307
$output = $commandTester->getDisplay();
285308
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Post', $output);
286-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index', $output);
309+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index ('.$i.' indexed since start)', $output);
287310
$this->assertStringContainsString('Done!', $output);
288311
$this->assertSame(0, $return);
289312
}
@@ -352,7 +375,7 @@ public function testImportsSelfNormalizable(): void
352375

353376
$this->assertSame(<<<'EOD'
354377
Importing for index Meilisearch\Bundle\Tests\Entity\SelfNormalizable
355-
Indexed 2 / 2 Meilisearch\Bundle\Tests\Entity\SelfNormalizable entities into sf_phpunit__self_normalizable index
378+
Indexed a batch of 2 / 2 Meilisearch\Bundle\Tests\Entity\SelfNormalizable entities into sf_phpunit__self_normalizable index (2 indexed since start)
356379
Done!
357380

358381
EOD, $importOutput);

tests/Integration/SearchTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ public function testSearchImportAggregator(): void
6969

7070
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Post', $output);
7171
$this->assertStringContainsString('Importing for index Meilisearch\Bundle\Tests\Entity\Tag', $output);
72-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index', $output);
73-
$this->assertStringContainsString('Indexed '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index', $output);
74-
$this->assertStringContainsString('Indexed 1 / 1 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index', $output);
75-
$this->assertStringContainsString('Indexed 1 / 1 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__'.self::$indexName.' index', $output);
72+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__posts index ('.$i.' indexed since start)', $output);
73+
$this->assertStringContainsString('Indexed a batch of '.$i.' / '.$i.' Meilisearch\Bundle\Tests\Entity\Post entities into sf_phpunit__'.self::$indexName.' index ('.$i.' indexed since start)', $output);
74+
$this->assertStringContainsString('Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__tags index (1 indexed since start)', $output);
75+
$this->assertStringContainsString('Indexed a batch of 1 / 1 Meilisearch\Bundle\Tests\Entity\Tag entities into sf_phpunit__'.self::$indexName.' index (1 indexed since start)', $output);
7676
$this->assertStringContainsString('Done!', $output);
7777

7878
$searchTerm = 'Test';

0 commit comments

Comments
 (0)