Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

28 multiple facettes selectable bib #48

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9eed946
Test one part authors
Nov 27, 2024
e3b8283
Add volume and number of volumes to footer
Nov 27, 2024
2558121
Merge pull request #40 from slub/main
dikastes Nov 28, 2024
ff11c90
Merge branch 'test' into 33-one-part-names
Nov 28, 2024
16242a8
Fixes
Nov 28, 2024
cd8f048
Merge pull request #38 from slub/33-one-part-names
dikastes Nov 28, 2024
24f9476
Merge branch 'test' into 34-number-of-volumes
Nov 28, 2024
caf9f4e
Fix tests
Nov 28, 2024
bd3ab8e
Merge pull request #37 from slub/34-number-of-volumes
dikastes Nov 28, 2024
c069a40
add alias handling and atomic swap and remove of old indexes
Dec 3, 2024
001ee8b
change selection of indexes to delete from wildcard alias to "zotero-…
Dec 4, 2024
1171610
fix remove _temp Alias on old indexes
Dec 4, 2024
1e385fb
Promote indexName to property
Dec 4, 2024
ea96685
Promote several variables to properties
Dec 4, 2024
6537123
Fixes
Dec 4, 2024
840b887
Merge pull request #43 from slub/21-copy-index-on-full-sync
dikastes Dec 4, 2024
28aaf7f
Add colon and add in to journal article footer
Dec 10, 2024
40ae182
Reorder facets and remove translators from creator facet
Dec 10, 2024
d8efe57
Add facet fields
Dec 10, 2024
ea8d019
Adjust test
Dec 10, 2024
9b22676
Adjust mapping
Dec 11, 2024
4bf7f7e
Merge pull request #47 from slub/44-small-changes
dikastes Dec 11, 2024
34bdebe
Change Mapping for separate FullName Fields
Jan 6, 2025
2d07dc4
Add creators field while indexing
Jan 6, 2025
b36764c
debug mapping and indexing (index only 3 docs)
Jan 6, 2025
4db61a3
optimize mappping and handling of nested fields
Jan 8, 2025
dbd35c6
Fix
Jan 6, 2025
9c6394b
Proposals for streamlining indexing
Jan 9, 2025
32b2a06
new entity type 'multiselect' for filters in setup.typoscript Filters…
Jan 13, 2025
4dcc5be
disable fetch localizedCitations and teiDataSets (temporary for more …
Jan 14, 2025
d0222a5
small refactoring for entityType multiselect (present or not, the val…
Jan 14, 2025
2586601
handle translations for bibliography facet items with own language fi…
Jan 14, 2025
21c52c2
Fix Bug if no creators exists
Jan 15, 2025
d796501
clean up code
Jan 15, 2025
94041f4
update translations for itemTypes
Jan 15, 2025
c4995f0
add entityType 'size' for number of facet items to display
Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 177 additions & 45 deletions Classes/Command/IndexCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,31 @@
class IndexCommand extends Command
{

protected ZoteroApi $bibApi;
const API_TRIALS = 3;

protected string $apiKey;
protected string $zoteroApiKey;
protected Collection $bibliographyItems;
protected Collection $deletedItems;
protected Collection $teiDataSets;
protected Collection $dataSets;
protected int $bulkSize;
protected Client $client;
protected Collection $dataSets;
protected Collection $deletedItems;
protected array $extConf;
readonly string $indexName;
protected InputInterface $input;
protected SymfonyStyle $io;
protected int $bulkSize;
protected int $total;
protected Collection $locales;
protected Collection $localizedCitations;
protected OutputInterface $output;
protected Collection $teiDataSets;
protected int $total;

public function __construct(
private readonly SiteFinder $siteFinder,
private readonly LoggerInterface $logger
) {
parent::__construct();
$this->extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('liszt_bibliography');
$this->indexName = $this->extConf['elasticIndexName'] . '_' . date('Ymd_His');
$this->initLocales();
}

Expand Down Expand Up @@ -100,20 +104,21 @@ protected function configure(): void

protected function initialize(InputInterface $input, OutputInterface $output): void
{
$this->extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('liszt_bibliography');
$this->input = $input;
$this->output = $output;
$this->client = ElasticClientBuilder::getClient();
$this->apiKey = $this->extConf['zoteroApiKey'];
$this->io = new SymfonyStyle($input, $output);
$this->zoteroApiKey = $this->extConf['zoteroApiKey'];
$this->io = GeneralUtility::makeInstance(SymfonyStyle::class, $this->input, $this->output);
$this->io->title($this->getDescription());
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->bulkSize = (int) $this->extConf['zoteroBulkSize'];
$version = $this->getVersion($input);
$version = $this->getVersion();
if ($version == 0) {
$this->io->text('Full data synchronization requested.');
$this->fullSync($input);
$this->fullSync();
$this->logger->info('Full data synchronization successful.');
} else {
$this->io->text('Synchronizing all data from version ' . $version);
Expand All @@ -123,17 +128,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return Command::SUCCESS;
}

protected function fullSync(InputInterface $input): void
protected function fullSync(): void
{
$client = new ZoteroApi($this->extConf['zoteroApiKey']);
$client = GeneralUtility::makeInstance(ZoteroApi::class, $this->zoteroApiKey);
$response = $client->
group($this->extConf['zoteroGroupId'])->
items()->
top()->
limit(1)->
send();
if ($input->getOption('total')) {
$this->total = (int) $input->getOption('total');
if ($this->input->getOption('total')) {
$this->total = (int) $this->input->getOption('total');
} else {
$this->total = (int) $response->getHeaders()['Total-Results'][0];
}
Expand All @@ -143,33 +148,45 @@ protected function fullSync(InputInterface $input): void
$collection = new Collection($response->getBody());
$this->bibliographyItems = $collection->pluck('data');
$cursor = 0; // set Cursor to 0, not to bulk size
$index = $this->extConf['elasticIndexName'];
$mappingParams = BibElasticMapping::getMappingParams($index);
// we are working with alias names to swap indexes from zotero_temp to zotero after successfully indexing
$tempIndexAlias = $this->extConf['elasticIndexName'].'_temp';
$tempIndexParams = BibElasticMapping::getMappingParams($this->indexName);

// add alias name 'zotero_temp to this index
// and add a wildcard alias to find all zotero_* indices with the alias zotero-index
$aliasParams = [
'body' => [
'actions' => [
[
'add' => [
'index' => $this->indexName,
'alias' => $tempIndexAlias,
],
],
[
'add' => [
'index' => $this->extConf['elasticIndexName'].'_*',
'alias' => $this->extConf['elasticIndexName'].'-index',
],
]
]
]
];

try {
// in older Elasticsearch versions (until 7) exists returns a bool
if ($this->client->indices()->exists(['index' => $index])) {
$this->client->indices()->delete(['index' => $index]);
$this->client->indices()->create($mappingParams);
}
$this->client->indices()->create($tempIndexParams);
$this->client->indices()->updateAliases($aliasParams);
} catch (\Exception $e) {
// other versions return a Message object
if ($e->getCode() === 404) {
$this->io->note("Index: " . $index . " does not exist. Trying to create new index.");
$this->client->indices()->create($mappingParams);
} else {
$this->io->error("Exception: " . $e->getMessage());
$this->logger->error('Bibliography sync unsuccessful. Error creating elasticsearch index.');
throw new \Exception('Bibliography sync unsuccessful.');
}
}

$apiCounter = self::API_TRIALS;

while ($cursor < $this->total) {
try {
$this->sync($cursor, 0);

$apiCounter = self::API_TRIALS;
$remainingItems = $this->total - $cursor;
$advanceBy = min($remainingItems, $this->bulkSize);
Expand All @@ -188,6 +205,11 @@ protected function fullSync(InputInterface $input): void
}
}
}

// swap alias for index from zotero_temp to zotero and remove old indexes (keep the last one)
$this->swapIndexAliases($tempIndexAlias);
//delete old indexes
$this->deleteOldIndexes();
$this->io->progressFinish();
}

Expand Down Expand Up @@ -217,28 +239,28 @@ protected function versionedSync(int $version): void
protected function sync(int $cursor = 0, int $version = 0): void
{
$this->fetchBibliography($cursor, $version);
$this->fetchCitations($cursor, $version);
$this->fetchTeiData($cursor, $version);
// $this->fetchCitations($cursor, $version);
// $this->fetchTeiData($cursor, $version);
$this->buildDataSets();
$this->commitBibliography();
}

protected function getVersion(InputInterface $input): int
protected function getVersion(): int
{
// if -a is specified, perfom a full update
if ($input->getOption('all')) {
if ($this->input->getOption('all')) {
return 0;
}

// also set version to 0 for dev tests if the total results are limited
if ($input->getOption('total')) {
$this->io->text('Total results limited to: '. $input->getOption('total'));
if ($this->input->getOption('total')) {
$this->io->text('Total results limited to: '. $this->input->getOption('total'));
return 0;
}


// if a version is manually specified, perform sync from this version
$argumentVersion = $input->getArgument('version');
$argumentVersion = $this->input->getArgument('version');
if ($argumentVersion > 0) {
return (int) $argumentVersion;
}
Expand Down Expand Up @@ -275,7 +297,7 @@ protected function getVersion(InputInterface $input): int

protected function fetchBibliography(int $cursor, int $version): void
{
$client = new ZoteroApi($this->extConf['zoteroApiKey']);
$client = GeneralUtility::makeInstance(ZoteroApi::class, $this->zoteroApiKey);
$response = $client->
group($this->extConf['zoteroGroupId'])->
items()->
Expand All @@ -291,7 +313,6 @@ protected function fetchBibliography(int $cursor, int $version): void

protected function fetchCitations(int $cursor, int $version): void
{
$this->localizedCitations = new Collection();
$this->locales->each(function($locale) use($cursor, $version) { $this->fetchCitationLocale($locale, $cursor, $version); });
}

Expand Down Expand Up @@ -320,7 +341,7 @@ protected function fetchCitationLocale(string $locale, int $cursor, int $version

protected function fetchTeiData(int $cursor, int $version): void
{
$client = new ZoteroApi($this->extConf['zoteroApiKey']);
$client = GeneralUtility::makeInstance(ZoteroApi::class, $this->zoteroApiKey);
$response = $client->
group($this->extConf['zoteroGroupId'])->
items()->
Expand All @@ -340,7 +361,13 @@ protected function buildDataSets(): void
{
$this->dataSets = $this->bibliographyItems->
map(function($bibliographyItem) {
return BibEntryProcessor::process($bibliographyItem, $this->localizedCitations, $this->teiDataSets);
return BibEntryProcessor::process(
$bibliographyItem,
new Collection(),
new Collection()
// $this->localizedCitations,
// $this->teiDataSets
);
});
}

Expand All @@ -350,15 +377,12 @@ protected function commitBibliography(): void
$this->io->text('no new bibliographic entries');
return;
}
$index = $this->extConf['elasticIndexName'];

$params = [ 'body' => [] ];

$bulkCount = 0;
foreach ($this->dataSets as $document) {
$params['body'][] = [ 'index' =>
[
'_index' => $index,
'_index' => $this->indexName,
'_id' => $document['key']
]
];
Expand All @@ -372,6 +396,114 @@ protected function commitBibliography(): void
$this->client->bulk($params);
}

protected function swapIndexAliases(string $tempIndexAlias): void
{
// get index with alias = zotero
try {
$aliasesRequest = $this->client->indices()->getAlias(['name' => $this->extConf['elasticIndexName']]);
$aliasesArray = $aliasesRequest->asArray();

foreach ($aliasesArray as $index => $aliasArray) {
$this->io->note('Remove alias "' .$this->extConf['elasticIndexName']. '" from index '. $index . ' and add it to ' . $this->indexName );
// get index name with alias 'zotero'
if (array_key_exists($this->extConf['elasticIndexName'], $aliasArray['aliases'])) {
//swap alias from old to new index
$aliasParams = [
'body' => [
'actions' => [
[
'remove' => [
'index' => $index,
'alias' => $this->extConf['elasticIndexName'],
],
],
[
'add' => [
'index' => $this->indexName,
'alias' => $this->extConf['elasticIndexName'],
],
],
[
'remove' => [
'index' => $this->indexName,
'alias' => $tempIndexAlias,
],
]
]
]
];
$this->client->indices()->updateAliases($aliasParams);
}
}
}
catch (\Exception $e) {
// other versions return a Message object
if ($e->getCode() === 404) {
$this->io->note("Alias: " . $this->extConf['elasticIndexName'] . " does not exist. Move alias to ".$this->indexName);
// rename alias name from temp index to zotero
$aliasParams = [
'body' => [
'actions' => [
[
'remove' => [
'index' => $this->indexName,
'alias' => $tempIndexAlias,
],
],
[
'add' => [
'index' => $this->indexName,
'alias' => $this->extConf['elasticIndexName'],
],
]
]
]
];
$this->client->indices()->updateAliases($aliasParams);

} else {
$this->io->error("Exception: " . $e->getMessage());
$this->logger->error('Bibliography sync unsuccessful. Error getting alias: ' . $this->extConf['elasticIndexName']);
throw new \Exception('Bibliography sync unsuccessful.', 0, $e);
}
}
}

protected function deleteOldIndexes(): void
{
try {
$aliasesRequest = $this->client->indices()->getAlias(['name' => $this->extConf['elasticIndexName'].'-index']);
$aliasesArray = $aliasesRequest->asArray();

// sort $aliasesArray by key name
ksort($aliasesArray);

// remove current key $indexName from array
unset($aliasesArray[$this->indexName]);

// remove the last key (we keep the last two indexes)
array_pop($aliasesArray);

foreach ($aliasesArray as $index => $aliasArray) {
$this->io->note("Delete index " . $index);
$this->client->indices()->delete(['index' => $index]);
}

}
catch (\Exception $e) {
// other versions return a Message object
if ($e->getCode() === 404) {
$this->io->note("Nothing to remove, there are no indexes with alias " . $this->extConf['elasticIndexName'].'-index');
} else {
$this->io->error("Exception: " . $e->getMessage());
$this->logger->error('Bibliography sync unsuccessful. Error getting alias: ' . $this->extConf['elasticIndexName'].'-index');
throw new \Exception('Bibliography sync unsuccessful.', 0, $e);
}
}


}

/* protected function commitLocales(): void
{
$localeIndex = $this->extConf['elasticLocaleIndexName'];
Expand Down
Loading
Loading