Skip to content

Feature Request: Optimized Batch Feature Evaluation with Shared UserContext for Memory Efficiency #184

Description

@shubham-300

Requesting a method to evaluate multiple features with a single shared UserContext to reduce memory usage when evaluating many features for the same user.

Problem Statement

When evaluating multiple features for the same user, we create a UserContext once and reuse it across evaluations. However, each call to evalFeature() or getFeatureValue() may create internal copies or duplicate data structures, leading to:

  • Higher memory usage when evaluating 50-100+ features per request
  • Unnecessary object allocations
  • Potential performance overhead from repeated context processing

Use Case

We have a high-throughput service that evaluates 50-100 features per user request. Currently, we:

// Create UserContext once
UserContext userContext = new UserContext.UserContextBuilder()
    .build()
    .witAttributesJson(attributesJson);

// Evaluate multiple features sequentially or in parallel
for (String featureName : featureNames) {
    FeatureResult<Object> result = client.evalFeature(
        featureName, 
        Object.class, 
        userContext  // Same context reused
    );
    // Process result...
}

While UserContext is immutable and thread-safe, the SDK may still create internal copies or process the context multiple times.

Current Behavior

  • Each evalFeature() call processes the UserContext independently
  • No explicit optimization for batch evaluation scenarios
  • Memory usage scales linearly with the number of features evaluated

Proposed Solution

Add a batch evaluation method that:

  1. Accepts a list of feature keys and a single UserContext
  2. Internally optimizes context processing (parse attributes once, reuse parsed data)
  3. Returns a map of feature keys to their evaluated results
  4. Minimizes memory allocations by sharing internal data structures

Proposed API:

// Option 1: New method on GrowthBookClient
Map<String, FeatureResult<Object>> evalFeatures(
    List<String> featureKeys,
    Class<Object> valueTypeClass,
    UserContext userContext
);

// Option 2: Builder pattern for batch operations
BatchEvaluator batchEvaluator = client.createBatchEvaluator(userContext);
Map<String, FeatureResult<Object>> results = batchEvaluator
    .evalFeatures(featureKeys, Object.class);

Benefits

  1. Memory efficiency: parse and process UserContext once for multiple features
  2. Performance: reduce redundant context processing
  3. API clarity: explicit batch evaluation method
  4. Backward compatible: existing single-feature methods remain unchanged

Example Implementation (Pseudo-code)

public Map<String, FeatureResult<ValueType>> evalFeatures(
    List<String> featureKeys,
    Class<ValueType> valueTypeClass,
    UserContext userContext
) {
    // Parse attributes once
    Map<String, Object> parsedAttributes = parseAttributes(userContext.getAttributesJson());
    
    // Pre-compute common context data
    EvaluationContext evalContext = buildEvaluationContext(userContext, parsedAttributes);
    
    // Evaluate all features using shared context
    Map<String, FeatureResult<ValueType>> results = new HashMap<>();
    for (String featureKey : featureKeys) {
        results.put(featureKey, evaluateFeature(featureKey, valueTypeClass, evalContext));
    }
    
    return results;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions