Skip to content

Searching

Mustang provides several ways to query criteria against an incoming event. All search operations accept a RequestContext wrapping a JsonNode event.

import com.fasterxml.jackson.databind.JsonNode;
import com.phonepe.mustang.common.RequestContext;

JsonNode event = mapper.readTree("{\"country\":\"IN\",\"age\":25}");
RequestContext context = RequestContext.builder().node(event).build();

The primary search method. Uses the inverted index (Conjunction or CNF algorithm) for sub-linear lookup.

// Unscored — fastest, returns all matching IDs
Set<String> ids = engine.search("my-index", context);

// Scored — returns all matching IDs, internally computes relevance scores
Set<String> ids = engine.search("my-index", context, true);

// Unscored explicit
Set<String> ids = engine.search("my-index", context, false);

// Top-N — returns only the N highest-scoring IDs
Set<String> ids = engine.search("my-index", context, 5);
Overload Scoring Returns
search(index, ctx) Off All matches
search(index, ctx, false) Off All matches
search(index, ctx, true) On All matches (ordered by relevance internally)
search(index, ctx, N) On Top-N matches only

Unscored vs. scored

Unscored search skips weight computation entirely — use it when you only need to know which criteria matched, not how well. Top-N search is often faster than full scoring for large match sets because it prunes candidates using score upper bounds.


scan — brute-force over an index

Evaluates every criteria in the named index one-by-one. Much slower than search for large indexes, but useful for:

  • Cross-checking search results (see Ratification)
  • Small in-memory indexes where indexing overhead is not worth it
Set<String> ids = engine.scan("my-index", context);

scan — evaluate an in-memory list

Evaluate a provided List<Criteria> directly, without any index:

List<Criteria> criteriaList = List.of(c1, c2, c3);
List<Criteria> matching = engine.scan(criteriaList, context);

Returns the Criteria objects themselves (not just IDs).


evaluate — single criteria check

Evaluate a single criteria against a context without any index lookup:

boolean result = engine.evaluate(criteria, context);

Equivalent to criteria.evaluate(context). No index required.


debug — per-predicate breakdown

Get a detailed result showing which conjunctions/disjunctions and predicates matched or failed:

DebugResult result = engine.debug(criteria, context);

result.isResult();                      // overall true/false
result.getId();                         // criteria ID
result.getForm();                       // DNF or CNF
result.getCompositionDebugResults();    // per-conjunction/disjunction breakdown
// Each CompositionDebugResult contains:
//   .isResult()               — whether this composition matched
//   .getPredicateDebugResults() — per-predicate detail

Example output structure:

DebugResult {
  id: "segment-001",
  form: DNF,
  result: true,
  compositionDebugResults: [
    {
      result: true,         ← first conjunction matched
      predicateResults: [
        { lhs: "$.country", result: true  },
        { lhs: "$.age",     result: true  }
      ]
    },
    {
      result: false,        ← second conjunction did not match
      predicateResults: [
        { lhs: "$.country", result: true  },
        { lhs: "$.platform",result: false }
      ]
    }
  ]
}

score — compute relevance score

// Score one criteria
double s = engine.score(criteria, context);

// Score a list — returns List<Pair<id, score>>
import org.apache.commons.lang3.tuple.Pair;
List<Pair<String, Double>> scores = engine.score(criteriaList, context);

See Scoring & Ranking for the formula.


JSONPath attribute references

The lhs field on every predicate is a JSONPath expression evaluated against the event JsonNode. Examples:

JSONPath Resolves to
$.country Top-level field country
$.user.age Nested field age inside user
$.tags[0] First element of array tags
$.meta.flags Nested object or array

Paths are evaluated using Jayway JsonPath. A missing path evaluates to null, which causes IncludedPredicate to return false and ExcludedPredicate to return true (WEAK-∉ semantics per the paper).