TagMatch matches per-user tag preferences (passed in a kvpairs clause) against per-document tag fields, then combines the resulting per-key scores into a final ranking weight. Use it in sort scripts to boost documents whose tags align with a user's interests.
How it works
Each search request carries a kvpairs clause that encodes the user's tag preferences as key-value pairs. TagMatch compares those keys against the document's tag field, computes a score for every matched key using kvOperatorName (or a constant kvResult), and then merges all per-key scores into a single value using mergeOperatorName. That value is added to the document's final sort score.
Use cases
Weighted tag matching
A forum assigns numeric IDs to content tags: funny = 1, sports = 5, news = 3, music = 6. Each post stores the IDs and their weights as a float array — for example, a post tagged funny (0.5), sports (0.5), and news (0.1) has a tag field value of [1 0.5 5 0.5 3 0.1].
After analyzing each member's reading history, you know their tag preferences. The member nba_fans favors sports (weight 0.6) and funny (weight 0.3). Pass those preferences in the kvpairs clause when they search: kvpairs=user_tag:5=0.6:1=0.3.
In your sort script, call TagMatch("user_tag", "tag", "mul", "sum", false, true, 50):
kvOperatorName = mul: multiply the query-side weight by the document-side weight for each matched tag.mergeOperatorName = sum: add the per-tag scores together.
When nba_fans finds that post, both sports and funny match:
Sports score: 0.5 × 0.6 = 0.3
Funny score: 0.5 × 0.3 = 0.15
Final TagMatch score: 0.3 + 0.15 = 0.45
That 0.45 is added to the document's overall sort score, surfacing the post higher for this user.
Key-only tag matching (no weights)
Clothing items carry attribute tags without weights: 1 = young, 2 = middle-aged, 3 = fresh, 4 = fashion, 5 = women, 6 = men. Items store the tag IDs in an options field as a key-only array — for example, [1 4 5] for a young, fashion, women item.
A user's historical purchases reveal she is young and female. When she searches, add kvpairs=user_options:1:3:5 to the request.
In your sort script, call TagMatch("user_options", "options", 10F, "sum", false, false):
kvResult = 10: each matched tag contributes a fixed score of 10.mergeOperatorName = sum: add all per-tag scores.fieldIsKv = false: the document field contains keys only, not key-value pairs.
Both young and women match → 10 + 10 = 20.
Prerequisites
Before you begin, ensure that you have:
An OpenSearch application with the Industry Algorithm Edition
A sort script that follows the CAVA
init/scorepatternA
kvpairsclause in your search request that carries the user's tag data
Create a TagMatch object
All TagMatch objects are created by calling TagMatch.create() in the init method of your scorer class. Call _tagMatch.evaluate(params) in the score method to compute and return the score.
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
// Replace the arguments below with your field names and operators.
_tagMatch = TagMatch.create(params, "user_tag", "tag", "mul", "sum", false, true, 50);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Parameters
create() with kvOperatorName (string operator)
Use this overload when you want to compute a per-key score by combining the query-side and document-side values with an operator (for example, mul to multiply them).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
params | OpsScorerInitParams | Yes | — | Score calculation parameters. See OpsScoreParams. |
queryKey | CString | Yes | — | Name of the field in the kvpairs clause that carries the user's tags. Keys and values are separated by =; pairs are separated by :. Example: kvpairs=query_tags:10=0.67:960=0.85:1=48. To pass keys only (no values), omit the =value part: kvpairs=cats:10:960:1. |
fieldName | CString | Yes | — | Name of the attribute field in documents that stores tags. Must be an integer or float array. Odd positions hold keys; even positions hold values: key0 value0 key1 value1. If the array is a float array, key values are converted to 64-bit integers during matching. |
kvOperatorName | CString | Yes | — | Operation applied to the query-side and document-side values for each matched key. Valid values: max (greater value), min (smaller value), avg (average), mul (product), query_value (use the query-side value), doc_value (use the document-side value). |
mergeOperatorName | CString | Yes | — | Operation applied to all per-key scores to produce the final TagMatch score. Valid values: max, min, sum, avg, first_match (use the score of the first matched key only). |
hasDefaultValue | boolean | No | false | If true, the first key-value pair in fieldName is used as the default score. The field format becomes default_score k0 v0 k1 v1. If false, there is no default. |
fieldIsKv | boolean | No | true | If true, the document field contains key-value pairs. If false, the document field contains keys only (no per-document weights). |
maxKvCount | int | No | 50 | Maximum number of key-value pairs from the queryKey field to match. Cannot exceed 5120. |
create() with kvResult (constant score)
Use this overload when every matched key should contribute the same fixed score, regardless of the values in either field — for example, when your document field contains keys only.
This overload takes the same parameters as the kvOperatorName overload, with one difference:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
kvResult | double | Yes | — | Fixed score returned for each matched key, replacing kvOperatorName. |
All other parameters (params, queryKey, fieldName, mergeOperatorName, hasDefaultValue, fieldIsKv, maxKvCount) behave identically to the kvOperatorName overload.
Overload reference
Both kvOperatorName and kvResult overloads come in four variants that drop trailing optional parameters and apply default values. The table below shows what defaults are applied when you omit trailing parameters.
kvOperatorName overload variants
| Signature (trailing params) | Omitted | Defaults applied |
|---|---|---|
..., hasDefaultValue, fieldIsKv, maxKvCount) | — | None |
..., hasDefaultValue, fieldIsKv) | maxKvCount | maxKvCount = 50 |
..., hasDefaultValue) | fieldIsKv, maxKvCount | fieldIsKv = true, maxKvCount = 50 |
..., mergeOperatorName) | hasDefaultValue, fieldIsKv, maxKvCount | hasDefaultValue = false, fieldIsKv = true, maxKvCount = 50 |
kvResult overload variants
| Signature (trailing params) | Omitted | Defaults applied |
|---|---|---|
..., hasDefaultValue, fieldIsKv, maxKvCount) | — | None |
..., hasDefaultValue, fieldIsKv) | maxKvCount | maxKvCount = 50 |
..., hasDefaultValue) | fieldIsKv, maxKvCount | fieldIsKv = true, maxKvCount = 50 |
..., mergeOperatorName) | hasDefaultValue, fieldIsKv, maxKvCount | hasDefaultValue = false, fieldIsKv = true, maxKvCount = 50 |
evaluate()
double evaluate(OpsScoreParams params)
Matches request tags against document tags and returns the combined score. Call this in your scorer's score method.
| Parameter | Type | Description |
|---|---|---|
params | OpsScoreParams | Score calculation parameters. See OpsScoreParams. |
Code samples
All examples use the same init / score class structure. The only difference is the TagMatch.create() call.
Full parameter set — kvOperatorName overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", "query_value",
"first_match", false, false, 100);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Default maxKvCount (50) — kvOperatorName overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", "query_value",
"first_match", false, false);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Default fieldIsKv (true) and maxKvCount (50) — kvOperatorName overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", "query_value",
"first_match", true);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}All defaults — kvOperatorName overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", "query_value",
"first_match");
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Full parameter set — kvResult overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", 3.3D,
"first_match", false, false, 100);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Default maxKvCount (50) — kvResult overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", 3.3D,
"first_match", false, false);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Default fieldIsKv (true) and maxKvCount (50) — kvResult overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", 3.3D,
"first_match", true);
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}All defaults — kvResult overload
package users.scorer;
import com.aliyun.opensearch.cava.framework.OpsScoreParams;
import com.aliyun.opensearch.cava.framework.OpsScorerInitParams;
import com.aliyun.opensearch.cava.framework.OpsRequest;
import com.aliyun.opensearch.cava.framework.OpsDoc;
import com.aliyun.opensearch.cava.features.TagMatch;
class BasicSimilarityScorer {
TagMatch _tagMatch;
boolean init(OpsScorerInitParams params) {
_tagMatch = TagMatch.create(params, "tag_match_key", "multi_int8", 3.3D,
"first_match");
return true;
}
double score(OpsScoreParams params) {
return _tagMatch.evaluate(params);
}
}Limitations
maxKvCountcannot exceed 5120.The
fieldNameattribute field must store values as an integer or float array. If a float array is used, key values are cast to 64-bit integers during matching.The search request must include a
kvpairsclause;TagMatchdoes not apply to requests without one.
What's next
kvpairs clause — syntax reference for passing tag data in search requests
OpsScoreParams — parameters available inside
evaluate()