diff --git a/specs/composition/common/schemas/components/CompositionBehavior.yml b/specs/composition/common/schemas/components/CompositionBehavior.yml index f41bea4bc76..10a8ca2f3df 100644 --- a/specs/composition/common/schemas/components/CompositionBehavior.yml +++ b/specs/composition/common/schemas/components/CompositionBehavior.yml @@ -41,6 +41,16 @@ compositionBehavior: maxItems: 2 items: $ref: '#/injectedItem' + deduplication: + title: deduplication + type: object + additionalProperties: false + description: Deduplication configures the methods used to resolve duplicate items between main search results and injected group results. + properties: + positioning: + $ref: '#/dedupPositioning' + required: + - positioning required: - main required: @@ -91,3 +101,17 @@ injectedItemSource: oneOf: - $ref: './InjectionSource.yml#/SearchSource' - $ref: './InjectionSource.yml#/ExternalSource' + +dedupPositioning: + type: string + enum: + - highest + - highestInjected + description: | + Deduplication positioning configures how a duplicate result should be resolved between an injected item and main search results. + Current configuration supports: + - 'highest': always select the item in the highest position, and remove duplicates that appear lower in the results. + - 'highestInjected': duplicate result will be moved to its highest possible injected position, but not higher. + If a duplicate appears higher in main search results, it will be removed to stay it's intended group position (which could be lower than main). + example: highest + default: highestInjected diff --git a/tests/CTS/requests/composition/multipleBatch.json b/tests/CTS/requests/composition/multipleBatch.json index 5fabb5d94a1..1f620e46fab 100644 --- a/tests/CTS/requests/composition/multipleBatch.json +++ b/tests/CTS/requests/composition/multipleBatch.json @@ -62,9 +62,7 @@ } }, { - "skipLanguages": [ - "kotlin" - ], + "skipLanguages": ["kotlin"], "parameters": { "requests": [ { @@ -147,9 +145,7 @@ } }, { - "skipLanguages": [ - "kotlin" - ], + "skipLanguages": ["kotlin"], "parameters": { "requests": [ { @@ -312,5 +308,86 @@ ] } } + }, + { + "skipLanguages": ["kotlin"], + "parameters": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "my-compo", + "name": "my composition", + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "foo" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "foo" + } + }, + "position": 2, + "length": 1 + } + ], + "deduplication": { + "positioning": "highest" + } + } + } + } + } + ] + }, + "request": { + "path": "/1/compositions/*/batch", + "method": "POST", + "body": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "my-compo", + "name": "my composition", + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "foo" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "foo" + } + }, + "position": 2, + "length": 1 + } + ], + "deduplication": { + "positioning": "highest" + } + } + } + } + } + ] + } + } } ] diff --git a/tests/CTS/requests/composition/putComposition.json b/tests/CTS/requests/composition/putComposition.json index f2fb892eb29..e95672ab842 100644 --- a/tests/CTS/requests/composition/putComposition.json +++ b/tests/CTS/requests/composition/putComposition.json @@ -134,9 +134,7 @@ } }, { - "skipLanguages": [ - "kotlin" - ], + "skipLanguages": ["kotlin"], "parameters": { "compositionID": "my-metadata-compo", "composition": { @@ -288,5 +286,80 @@ } } } + }, + { + "parameters": { + "compositionID": "my-compo", + "composition": { + "objectID": "my-compo", + "name": "my composition", + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "foo", + "params": { + "filters": "brand:adidas" + } + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "foo" + } + }, + "position": 2, + "length": 1 + } + ], + "deduplication": { + "positioning": "highest" + } + } + } + } + }, + "request": { + "path": "/1/compositions/my-compo", + "method": "PUT", + "body": { + "objectID": "my-compo", + "name": "my composition", + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "foo", + "params": { + "filters": "brand:adidas" + } + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "foo" + } + }, + "position": 2, + "length": 1 + } + ], + "deduplication": { + "positioning": "highest" + } + } + } + } + } } ] diff --git a/tests/CTS/requests/composition/putCompositionRule.json b/tests/CTS/requests/composition/putCompositionRule.json index b27b2478f0c..42c96f71900 100644 --- a/tests/CTS/requests/composition/putCompositionRule.json +++ b/tests/CTS/requests/composition/putCompositionRule.json @@ -78,9 +78,7 @@ } }, { - "skipLanguages": [ - "kotlin" - ], + "skipLanguages": ["kotlin"], "parameters": { "compositionID": "compositionID", "objectID": "rule-with-metadata", @@ -197,10 +195,7 @@ "compositionRule": { "objectID": "rule-with-exernal-source", "description": "my description", - "tags": [ - "tag1", - "tag2" - ], + "tags": ["tag1", "tag2"], "enabled": true, "validity": [ { @@ -258,10 +253,7 @@ "body": { "objectID": "rule-with-exernal-source", "description": "my description", - "tags": [ - "tag1", - "tag2" - ], + "tags": ["tag1", "tag2"], "enabled": true, "validity": [ { @@ -313,5 +305,93 @@ } } } + }, + { + "parameters": { + "compositionID": "compositionID", + "objectID": "rule-with-deduplication", + "compositionRule": { + "objectID": "rule-with-deduplication", + "description": "my description", + "enabled": true, + "conditions": [ + { + "anchoring": "contains", + "pattern": "harry" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "my-index" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "my-index" + } + }, + "position": 0, + "length": 3 + } + ], + "deduplication": { + "positioning": "highestInjected" + } + } + } + } + } + }, + "request": { + "path": "/1/compositions/compositionID/rules/rule-with-deduplication", + "method": "PUT", + "body": { + "objectID": "rule-with-deduplication", + "description": "my description", + "enabled": true, + "conditions": [ + { + "anchoring": "contains", + "pattern": "harry" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "my-index" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "my-index" + } + }, + "position": 0, + "length": 3 + } + ], + "deduplication": { + "positioning": "highestInjected" + } + } + } + } + } + } } ] diff --git a/tests/CTS/requests/composition/saveRules.json b/tests/CTS/requests/composition/saveRules.json index 03069a1db1f..c525a5dcb04 100644 --- a/tests/CTS/requests/composition/saveRules.json +++ b/tests/CTS/requests/composition/saveRules.json @@ -65,9 +65,7 @@ } }, { - "skipLanguages": [ - "kotlin" - ], + "skipLanguages": ["kotlin"], "parameters": { "compositionID": "rule-with-metadata", "rules": { @@ -200,10 +198,7 @@ "body": { "objectID": "rule-with-exernal-source", "description": "my description", - "tags": [ - "tag1", - "tag2" - ], + "tags": ["tag1", "tag2"], "enabled": true, "validity": [ { @@ -268,10 +263,7 @@ "body": { "objectID": "rule-with-exernal-source", "description": "my description", - "tags": [ - "tag1", - "tag2" - ], + "tags": ["tag1", "tag2"], "enabled": true, "validity": [ { @@ -326,5 +318,106 @@ ] } } + }, + { + "parameters": { + "compositionID": "my-compo", + "rules": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "rule-with-deduplication", + "description": "my description", + "enabled": true, + "conditions": [ + { + "anchoring": "contains", + "pattern": "harry" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "my-index" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "my-index" + } + }, + "position": 0, + "length": 3 + } + ], + "deduplication": { + "positioning": "highestInjected" + } + } + } + } + } + } + ] + } + }, + "request": { + "path": "/1/compositions/my-compo/rules/batch", + "method": "POST", + "body": { + "requests": [ + { + "action": "upsert", + "body": { + "objectID": "rule-with-deduplication", + "description": "my description", + "enabled": true, + "conditions": [ + { + "anchoring": "contains", + "pattern": "harry" + } + ], + "consequence": { + "behavior": { + "injection": { + "main": { + "source": { + "search": { + "index": "my-index" + } + } + }, + "injectedItems": [ + { + "key": "my-unique-injected-item-key", + "source": { + "search": { + "index": "my-index" + } + }, + "position": 0, + "length": 3 + } + ], + "deduplication": { + "positioning": "highestInjected" + } + } + } + } + } + } + ] + } + } } ]