diff --git a/src/Application/Config.php b/src/Application/Config.php index 7495c54..5eea943 100644 --- a/src/Application/Config.php +++ b/src/Application/Config.php @@ -15,6 +15,7 @@ public function __construct( private readonly ?PropertyId $itemTypeProperty = null, private readonly ?FacetConfigList $facets = null, private readonly ?array $icons = null, + public readonly bool $indexAllProperties = false ) { } @@ -73,4 +74,16 @@ public function isComplete(): bool { return $this->itemTypeProperty !== null; } + /** + * @return PropertyId[] + */ + public function getPropertiesWithFacetsForItemType( ItemId $itemType ): array { + return array_values( + array_map( + fn( FacetConfig $config ) => $config->propertyId, + $this->getFacetConfigForItemType( $itemType ) + ) + ); + } + } diff --git a/src/Application/StatementListTranslator.php b/src/Application/StatementListTranslator.php index 0b49fe8..1938c09 100644 --- a/src/Application/StatementListTranslator.php +++ b/src/Application/StatementListTranslator.php @@ -29,7 +29,7 @@ public function translateStatements( StatementList $statements ): array { return []; } - $propertyIds = $this->getPropertiesToIndex( $itemType ); + $propertyIds = $this->getPropertiesToIndex( $itemType, $statements ); $values = []; @@ -43,13 +43,15 @@ public function translateStatements( StatementList $statements ): array { /** * @return PropertyId[] */ - private function getPropertiesToIndex( ItemId $itemType ): array { - $properties = array_values( - array_map( - fn( FacetConfig $config ) => $config->propertyId, - $this->config->getFacetConfigForItemType( $itemType ) - ) - ); + private function getPropertiesToIndex( ItemId $itemType, StatementList $statements ): array { + if ( $this->config->indexAllProperties ) { + // TODO: is this sufficient, or do we need to end up explicitly indexing properties not present as empty? + $properties = $statements->getPropertyIds(); + } + else { + $properties = $this->config->getPropertiesWithFacetsForItemType( $itemType ); + } + $properties[] = $this->config->getItemTypeProperty(); return $properties; diff --git a/src/Persistence/ConfigDeserializer.php b/src/Persistence/ConfigDeserializer.php index d3ef2a6..ea9c9d8 100644 --- a/src/Persistence/ConfigDeserializer.php +++ b/src/Persistence/ConfigDeserializer.php @@ -40,6 +40,7 @@ private function newConfig( array $configArray ): Config { itemTypeProperty: $this->newPropertyId( $configArray['itemTypeProperty'] ?? null ), facets: $this->newFacetConfigList( $configArray['configPerItemType'] ?? [] ), icons: $this->newIconsList( $configArray['configPerItemType'] ?? [] ), + indexAllProperties: (bool)( $configArray['indexAllProperties'] ?? false ), ); } diff --git a/src/config-example.json b/src/config-example.json index 66092ec..7316aec 100644 --- a/src/config-example.json +++ b/src/config-example.json @@ -1,5 +1,4 @@ { - "sitelinkSiteId": "enwiki", "itemTypeProperty": "P42", "configPerItemType": { "Q100": { @@ -28,5 +27,7 @@ } } } - } + }, + "sitelinkSiteId": "enwiki", + "indexAllProperties": true } diff --git a/src/config-schema.json b/src/config-schema.json index b8ab13d..6451e91 100644 --- a/src/config-schema.json +++ b/src/config-schema.json @@ -10,6 +10,10 @@ "type": [ "string", "null" ], "pattern": "^P[1-9]\\d{0,9}$" }, + "indexAllProperties": { + "type": "boolean", + "default": false + }, "configPerItemType": { "type": "object", "propertyNames": { diff --git a/templates/ConfigurationDocumentation.mustache b/templates/ConfigurationDocumentation.mustache index a900dc8..421e036 100644 --- a/templates/ConfigurationDocumentation.mustache +++ b/templates/ConfigurationDocumentation.mustache @@ -254,6 +254,35 @@ } +
+

Index All Properties

+ +

+ By default the extension will index only values for properties for which facets are configured. + Via this setting, you can make the extension index values for all properties instead. +

+ +

+ Indexing values for all properties is useful + when you want to be able to run structured queries for properties not shown in the UI. It is also + useful to avoid having to rebuild the search index whenever you add a new property to the UI. +

+ +

+ Downsides of indexing values for all properties include needing additional storage space for the + search index and increased time and CPU resources to (re)build said index. +

+ +

+ Example configuration: +

+ +
+{
+	"indexAllProperties": true
+}
+
+

{{msg-wikibase-faceted-search-config-help-example}}

diff --git a/tests/phpunit/Application/ConfigTest.php b/tests/phpunit/Application/ConfigTest.php index cebd296..491352b 100644 --- a/tests/phpunit/Application/ConfigTest.php +++ b/tests/phpunit/Application/ConfigTest.php @@ -180,4 +180,25 @@ public function testGetIconForItemType(): void { $this->assertNull( $config->getIconForItemType( $q3 ) ); } + public function testGetPropertiesWithFacetsForItemType(): void { + $config = new Config( + sitelinkSiteId: 'enwiki', + itemTypeProperty: new NumericPropertyId( 'P42' ), + facets: new FacetConfigList( + new FacetConfig( new ItemId( 'Q100' ), new NumericPropertyId( 'P2' ), FacetType::LIST ), + new FacetConfig( new ItemId( 'Q200' ), new NumericPropertyId( 'P3' ), FacetType::LIST ), + new FacetConfig( new ItemId( 'Q100' ), new NumericPropertyId( 'P4' ), FacetType::LIST ), + new FacetConfig( new ItemId( 'Q200' ), new NumericPropertyId( 'P5' ), FacetType::LIST ), + ) + ); + + $this->assertEquals( + [ + new NumericPropertyId( 'P2' ), + new NumericPropertyId( 'P4' ), + ], + $config->getPropertiesWithFacetsForItemType( new ItemId( 'Q100' ) ) + ); + } + } diff --git a/tests/phpunit/Application/StatementListTranslatorTest.php b/tests/phpunit/Application/StatementListTranslatorTest.php index cfbaaed..f97f41f 100644 --- a/tests/phpunit/Application/StatementListTranslatorTest.php +++ b/tests/phpunit/Application/StatementListTranslatorTest.php @@ -63,10 +63,12 @@ public function testTranslatesStatementsForAllConfiguredProperties(): void { $itemType = new ItemId( 'Q100' ); $propertyP1 = new NumericPropertyId( 'P100' ); $propertyP2 = new NumericPropertyId( 'P200' ); + $propertyP3 = new NumericPropertyId( 'P300' ); $statements = new StatementList( $this->newStatement( $propertyP1, new StringValue( 'unimportant' ) ), $this->newStatement( $propertyP2, new StringValue( 'unimportant' ) ), + $this->newStatement( $propertyP3, new StringValue( 'unimportant' ) ), ); $config = new Config( @@ -78,17 +80,22 @@ public function testTranslatesStatementsForAllConfiguredProperties(): void { type: FacetType::LIST ), new FacetConfig( - itemType: $itemType, + itemType: new ItemId( 'Q404' ), // Different item type, so not indexed propertyId: $propertyP2, type: FacetType::LIST ), + new FacetConfig( + itemType: $itemType, + propertyId: $propertyP3, + type: FacetType::LIST + ), ) ); $this->assertEquals( [ 'wbfs_P100' => [ 'translated value' ], - 'wbfs_P200' => [ 'translated value' ], + 'wbfs_P300' => [ 'translated value' ], 'wbfs_P42' => [], ], $this->newTranslator( @@ -131,4 +138,44 @@ public function testFiltersNullValues(): void { ); } + public function testTranslatesAllStatementsWhenIndexAllPropertiesIsTrue(): void { + $propertyP1 = new NumericPropertyId( 'P100' ); + $propertyP2 = new NumericPropertyId( 'P200' ); + + $statements = new StatementList( + $this->newStatement( $propertyP1, new StringValue( 'unimportant' ) ), + $this->newStatement( $propertyP2, new StringValue( 'unimportant' ) ), + ); + + $config = new Config( + itemTypeProperty: new NumericPropertyId( 'P42' ), + facets: new FacetConfigList( + new FacetConfig( + itemType: new ItemId( 'Q100' ), + propertyId: $propertyP1, + type: FacetType::LIST + ), + new FacetConfig( + itemType: new ItemId( 'Q200' ), + propertyId: $propertyP2, + type: FacetType::LIST + ), + ), + indexAllProperties: true + ); + + $this->assertEquals( + [ + 'wbfs_P100' => [ 'translated value' ], + 'wbfs_P200' => [ 'translated value' ], + 'wbfs_P42' => [], + ], + $this->newTranslator( + statementTranslator: new StubStatementTranslator( 'translated value' ), + itemTypeExtractor: new StubItemTypeExtractor( new ItemId( 'Q300' ) ), + config: $config + )->translateStatements( $statements ) + ); + } + } diff --git a/tests/phpunit/Persistence/ConfigDeserializerTest.php b/tests/phpunit/Persistence/ConfigDeserializerTest.php index e7c7fc7..d8fa2a3 100644 --- a/tests/phpunit/Persistence/ConfigDeserializerTest.php +++ b/tests/phpunit/Persistence/ConfigDeserializerTest.php @@ -146,4 +146,30 @@ public function testDefaultsToEmptyTypeSpecificConfig(): void { ); } + public function testCanSetIndexAllProperties(): void { + $config = $this->newDeserializer()->deserialize( '{ + "indexAllProperties": true +} +' ); + + $this->assertTrue( $config->indexAllProperties ); + } + + public function testDefaultsToNotIndexAllProperties(): void { + $config = $this->newDeserializer()->deserialize( '{ +} +' ); + + $this->assertFalse( $config->indexAllProperties ); + } + + public function testCanSetIndexAllPropertiesToFalse(): void { + $config = $this->newDeserializer()->deserialize( '{ + "indexAllProperties": false +} +' ); + + $this->assertFalse( $config->indexAllProperties ); + } + }