FeatureGenerator (FG) is a data transformation process that converts raw inputs into model-ready features. It is designed to ensure consistency between offline and online sample generation. This process is also known as feature transformation, which transforms one or more features. Various types of feature operators are available to perform these operations.
Feature generation focuses only on transformations required for both offline and online sample generation. If a transformation operation is required only in the offline stage, do not define it as an FG operation. The following diagram shows the position of the FG module in a recommendation system architecture.
The feature generation process consists of a series of feature operators (FG operators) that are executed in parallel according to the topological order of a directed acyclic graph (DAG) defined in the configuration file.
Configuration file example
Configure feature operators in the features list. Each feature operator must include the feature_name and feature_type parameters. For other configuration parameters, see Built-in feature operators.
The reserves parameter specifies the fields to be passed through from an offline task, which are output as-is without feature transformation.
{
"features": [
{
"feature_name": "goods_id",
"feature_type": "id_feature",
"value_type": "string",
"expression": "item:goods_id",
"default_value": "-1024",
"need_prefix": false
},
{
"feature_name": "color_pair",
"feature_type": "combo_feature",
"value_type": "string",
"expression": ["user:query_color", "item:color"],
"default_value": "",
"need_prefix": false
},
{
"feature_name": "current_price",
"feature_type": "raw_feature",
"value_type": "double",
"expression": "item:current_price",
"default_value": "0",
"need_prefix": false
},
{
"feature_name": "usr_cate1_clk_cnt_1d",
"feature_type": "lookup_feature",
"map": "user:usr_cate1_clk_cnt_1d",
"key": "item:cate1",
"need_discrete": false,
"need_key": false,
"default_value": "0",
"combiner": "max",
"need_prefix": false,
"value_type": "double"
},
{
"feature_name": "recommend_match",
"feature_type": "overlap_feature",
"method": "is_contain",
"query": "user:query_recommend",
"title": "item:recommend",
"default_value": "0"
},
{
"feature_name": "norm_title",
"feature_type": "text_normalizer",
"expression": "item:title",
"max_length": 512,
"parameter": 0,
"remove_space": false,
"is_gbk_input": false,
"is_gbk_output": false
},
{
"feature_name": "title_terms",
"feature_type": "tokenize_feature",
"expression": "feature:norm_title",
"default_value": "",
"vocab_file": "tokenizer.json",
"output_type": "word_id",
"output_delim": ","
},
{
"feature_name": "query_title_match_ratio",
"feature_type": "overlap_feature",
"method": "query_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "title_term_match_ratio",
"feature_type": "overlap_feature",
"method": "title_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "term_proximity_min_cover",
"feature_type": "overlap_feature",
"method": "proximity_min_cover",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
}
],
"input_alias": {
"non_exist_field1": "exist_field1",
"non_exist_field2": "exist_field2"
},
"reserves": [
"request_id",
"user_id",
"is_click",
"is_pay",
"sample_weight",
"event_unix_time"
]
}Special configuration item input_alias: A dictionary that maps a potentially non-existent input field name to an actual field name. (The input_alias configuration is supported in version 1.0.0 and later. You can usually skip this configuration.)
Use case 1: Set a shorter alias for a long field name.
Use case 2: Set an alias for the second parameter when a custom feature operator uses the same input for two different parameters.
The same input field can be reused across different features, but cannot be reused within a single feature transformation. You can configure input_alias to bypass this restriction.
For example, if a custom feature operator has two input parameters that both require the same field
A, you can configure two inputs,AandB, and aninput_aliasto map"B": "A". At runtime, the parameters for the custom feature operator are changed from (A, B) to (A, A).
Input domains
An input domain indicates the entity from which an input originates. The following four types are supported:
user: User-side features, including user profiles and user-level statistical features.
context: Contextual features that change with each request, such as time, location, and weather.
item: Item-side features, including static content features and item-level statistical features.
feature: The output of another feature operator.
The feature input domain is special; it configures dependencies between feature operators. Collectively, all feature operators form a directed acyclic graph (DAG). The framework executes these feature transformation operations in parallel according to the topological order. The topology is shown in the following figure.
By default, the output of intermediate nodes in a DAG is not used as the output of the FG. You can use the stub_type feature configuration parameter to change this behavior.
Multi-value types and separators
FG supports complex input types, such as Array and Map, which are consistent with the complex types in MaxCompute.
String-type multi-valued features can use chr(29) as a delimiter.
For example, in v1^]v2^]v3, ^] is the multi-value separator. It is a single character with the ASCII code "\x1D", not two characters. To enter this character, press C-q C-5 in emacs or C-v C-5 in vi.
Feature binning (discretization)
The framework supports the following six types of binning operations:
hash_bucket_size: Hashes the feature transformation result and applies a modulo operation.
vocab_list: Maps the feature transformation result to an index in a list.
vocab_dict: Maps the feature transformation result to a value in a dictionary. The value must be convertible to the int64 type.
vocab_file: Reads a
vocab_listorvocab_dictfrom a file.boundaries: Converts the feature transformation result to a corresponding bucket ID based on specified boundaries.
num_buckets: Uses the feature transformation result directly as the bucket ID.
hash_bucket_size
Hashes the transformation result and applies a modulo operation. This method is applicable to any feature value type.
Result range: [0,
hash_bucket_size)The feature binning result for an empty value is
hash(default_value)%hash_bucket_size.
{
"hash_bucket_size": 128000,
"default_value": "default_value"
}vocab_list
Bins the input by mapping a feature value to its corresponding index in the vocab_list array.
The element type of the
vocab_listarray must be the same as thevalue_typeconfiguration.num_oov_bucket: Non-negative integer, the number of out-of-vocabulary buckets.All out-of-vocabulary inputs will be assigned IDs in the range [vocabulary_size, vocabulary_size+num_oov_buckets) based on a hash of the input value.
A positive num_oov_buckets cannot be specified with
default_bucketize_value.
default_bucketize_value: The integer ID value to return for out-of-vocabulary feature values.You cannot specify this when
num_oov_bucketsis positive.The default value is
vocab_list.size().
{
"vocab_list": [
"",
"<OOV>",
"token1",
"token2",
"token3",
"token4"
],
"num_oov_bucket": 0,
"default_bucketize_value": 1
}vocab_dict
The binning result is the value in the vocab_dict dictionary that corresponds to the feature value. This supports mapping different feature values to the same binning result.
The data type of the keys in the
vocab_dictdictionary must be the same as thevalue_typeconfiguration.The value of
vocab_dictmust be convertible to theint64type.num_oov_bucket: Non-negative integer, the number of out-of-vocabulary buckets.All out-of-vocabulary inputs will be assigned IDs in the range [vocabulary_size, vocabulary_size+num_oov_buckets) based on a hash of the input value.
A positive num_oov_buckets cannot be specified with
default_bucketize_value.
default_bucketize_value: The integer ID value to return for out-of-vocabulary feature values.This cannot be specified with a positive
num_oov_buckets.The default value is
vocab_dict.size().
{
"vocab_dict": {
"token1": 1,
"token2": 2,
"token3": 3,
"token4": 1
},
"num_oov_bucket": 0,
"default_bucketize_value": 4
}vocab_file
Loads a vocab_list or vocab_dict from a file.
{
"vocab_file": "vocab.txt",
"num_oov_bucket": 0,
"default_bucketize_value": 4
}vocab_file: The path to the vocabulary file. The file contains a vocabulary, with one term per line. You can optionally specify a mapping value.Relative paths are supported. When you deploy the online service, it must be placed in the same directory as
fg.json.If only a token is present, it is mapped to the line number (starting from 0). If a value is present, the token and the value are separated by a whitespace character (a space or a tab). The value must be of the
int64type.
num_oov_bucketanddefault_bucketize_valuehave the same meaning as described above.
boundaries
Buckets numerical features based on specified bin boundaries.
The element type of the
boundariesarray must be the same as thevalue_typeconfiguration.Buckets include the left boundary and exclude the right boundary.
For example,
boundaries=[0., 1., 2.]generates buckets (-inf, 0.), [0., 1.), [1., 2.), and [2., +inf).
{
"boundaries": [0.0, 1.0, 2.0],
"default_value": -1
}num_buckets
Uses the feature transformation result directly as the bucket ID. This method is suitable for feature values that can be converted to an integer.
Result range: [0,
num_buckets)If the feature value is outside the configured range, it is assigned
default_bucketize_value.
{
"num_buckets": 128000,
"default_bucketize_value": 127999
}Built-in feature operators
Configuration methods vary among feature operators. All feature operators that can be leaf nodes in the DAG support feature binning.
For more information, see Built-in feature operators.
Type | Description |
id_feature | categorical feature |
raw_feature | numerical feature |
expr_feature | expression feature |
combo_feature | combination feature |
combine_feature | combination feature (aggregated to a single value) |
lookup_feature | dictionary lookup feature |
match_feature | primary-secondary key dictionary lookup feature |
overlap_feature | overlap feature |
sequence_feature | sequence feature |
text_normalizer | text normalization |
tokenize_feature | text tokenization feature |
bm25_feature | BM25 text relevance feature |
kv_dot_product | KV vector dot product |
str_replace_feature | String replacement |
regex_replace_feature | Regular expression replacement |
slice_feature | Array slicing |
Operator combinations
By configuring a DAG, you can combine various built-in operators to perform powerful feature transformations.
Example 1: Average the first 4 sequence elements
{
"features": [
{
"feature_name": "top_n_prices",
"feature_type": "sequence_raw_feature",
"expression": "user:clk_prices",
"separator": ",",
"sequence_length": 4,
"stub_type": true
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}Example 2: Average sequence elements with a condition
{
"features": [
{
"feature_name": "valid_list",
"feature_type": "expr_feature",
"expression":"clk_times < 10",
"variables":["user:clk_times"],
"value_dimension": 5
},
{
"feature_name": "top_n_prices",
"feature_type": "bool_mask_feature",
"expression": ["user:clk_prices", "feature:valid_list"],
"value_type": "float",
"separator": ","
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}Note: In the preceding example, clk_prices and clk_times are two parallel sequences.
Custom feature operators
Custom feature operators can be dynamically loaded and executed by the framework as plugins.
For more information, see Custom feature operators.
Performance optimization
The performance of the FG module is highly dependent on its configuration. The general principle is to minimize unnecessary data (feature) transformations.
If you can process and transform data in the offline or near-line stages, do not perform them in the FG stage (online scoring service).
Follow these guidelines for better performance:
For structured input data, prioritize using complex types from MaxCompute tables (for example, Map and Array) instead of the STRING type to reduce string parsing overhead.
In online scoring services (such as EasyRec Processor or TorchEasyRec Processor), use FeatureStore and FeatureDB as the online storage to enable support for complex types.
For a
lookup_feature, using the Map type for themapfield is highly recommended.For
sequence_feature,overlap_feature, andbm25_feature, using Array-type inputs is highly recommended.Avoid using
match_featurebecause it does not support complex types. Uselookup_featureinstead by combiningpkeyandskey.
Avoid the overhead of data type conversion.
The
value_typeofraw_featureshould not be set to a type other than float without a specific reason.For a
lookup_feature, ensure that the key type of theMap<Key, Value>input matches the type of the query field.If you configure feature binning of the
num_bucketstype,value_typemust be set toint64.If the optimal type for a data column varies across different scenarios, consider adding a copy of the column with a different type.
For example, a field must be a BIGINT when used as the lookup field for
lookup_feature, but a STRING when used as part ofcombo_feature.In this case, add a copy of the column for each required type: one BIGINT and one STRING. The following is sample SQL code:
SELECT int_data, int_data as str_data FROM ....
Reuse shared logic and computations whenever possible by using feature dependencies (DAG mode).
Global configuration
Parameter | Type | Default | Description |
USE_CITY_HASH_TO_BUCKETIZE | string | 'false' | Specifies whether to use CityHash as the hash function for feature binning. |
USE_MULTIPLICATIVE_HASH | string | 'false' | Specifies whether to use multiplicative hashing instead of the modulo operation for feature hashing. This option is recommended. |
DISABLE_FG_PRECISION | string | 'true' | Set to 'false' to constrain floating-point features to six decimal places. The default is 'true', which disables this constraint. |
DISABLE_STRING_TRIM | string | 'false' | Specifies whether to disable the trimming of leading and trailing spaces after splitting multi-value string features. |
MONITOR_CUSTOM_OP_EVERY_N_SECONDS | string | '0' | Specifies the interval in seconds for monitoring the performance of custom operators and printing performance data. A value of '0' disables monitoring. |
Note: The preceding configurations must be consistent across all execution environments, including offline and online, as well as for training and inference. Otherwise, inconsistencies may occur between online and offline scoring.
Hash collision rate
The following shows the test results on a dataset with 26 features of different cardinalities, where the hash_bucket_size for each feature is set to 10 × its cardinality:
Hash type | Total feature cardinality | Total bins | Hash collision rate |
std::hash | 882,774,549 | 840,065,238 | 4.8381% |
cityhash | 882,774,549 | 840,072,446 | 4.8373% |
std+cityhash | 882,774,549 | 840,075,948 | 4.8369% |
cityhash+multiplicative | 882,774,549 | 840,072,195 | 4.8373% |
std+multiplicative | 882,774,549 | 840,077,306 | 4.8367% |
In summary, we recommend using std::hash + MultiplicativeHash as a combined approach to optimize model performance. std::hash is enabled by default. MultiplicativeHash is disabled by default for backward compatibility, and you must manually enable it by following the instructions below.
Additionally, CityHash is a method that theoretically offers better uniformity, but it did not show a significant advantage on this dataset. You can test it further on your own dataset.
Online scoring service configuration
Configure these settings by using server-side environment variables. Specifically, you can set them in the service configuration of EasyRec Processor or TorchEasyRec Processor.
{
"processor_envs": [
{
"name": "USE_MULTIPLICATIVE_HASH",
"value": "true"
}
]
}Offline job configuration
To run offline tasks for FG in the MaxCompute environment, see Use FG in offline tasks.
Specifically, refer to the following code:
from pyfg105 import run_on_odps
fg_task = run_on_odps.FgTask(...)
fg_task.add_fg_setting('USE_CITY_HASH_TO_BUCKETIZE', 'false')
fg_task.add_fg_setting('USE_MULTIPLICATIVE_HASH', 'true')
fg_task.run(o)pyfg API configuration
When using the pyfg API, for example to perform feature generation during training, you can configure it by using the following method.
import pyfg
pyfg.set_env('USE_MULTIPLICATIVE_HASH', 'true')
pyfg.set_env('USE_CITY_HASH_TO_BUCKETIZE', 'false')