Class ByteMatchers
All operations are byte-level — they treat their inputs as opaque byte[] and
make no assumption about character encoding or case. Callers that work with valid UTF-8 KEYWORD
values (the Elasticsearch contract) get codepoint-correct semantics for free thanks to UTF-8's
self-synchronizing property: a valid UTF-8 substring matches at byte boundaries iff it matches
at codepoint boundaries. For inputs that are not valid UTF-8, the helpers degrade to plain byte
comparison — caller's responsibility if that diverges from the desired semantics.
Each primitive routes the heavy lifting through the fastest implementation available on the platform:
equals(BytesRef, BytesRef),startsWith(BytesRef, BytesRef),endsWith(BytesRef, BytesRef)delegate toArrays.equals(byte[], int, int, byte[], int, int), which HotSpot intrinsifies to AVX2/AVX-512 on x86 and NEON on ARM (with partial-inlining for sizes ≤ 64 bytes — no stub call).containsLiteral(BytesRef, BytesRef)delegates toBinaryDocValuesContainsTermQuery.contains(byte[], int, int, BytesRef), a thin wrapper overESVectorUtil#containswhich uses Panama Vector API first+last byte filtering for values ≥ 24 bytes.
The methods are deliberately small and inlinable so the JIT can fuse them into per-row predicate loops without virtual-call overhead. Datasource evaluators (today: Parquet late-materialization; future: any in-Java filter on byte-shaped columns) should call these helpers rather than open-coding the byte loops.
-
Method Summary
Modifier and TypeMethodDescriptionstatic booleanaffixContains(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef prefix, org.apache.lucene.util.BytesRef literal, org.apache.lucene.util.BytesRef suffix) Composite predicate: returnstrueiffvaluestarts withprefix, ends withsuffix, and containsliteralas a contiguous subsequence anywhere between the matched prefix and suffix.static booleancontainsLiteral(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef literal) Returnstrueiffvaluecontainsliteralas a contiguous subsequence.static booleanendsWith(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef suffix) Returnstrueiffvalueends withsuffix.static booleanequals(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef target) Returnstrueiff the two byte sequences have identical length and content.static booleanstartsWith(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef prefix) Returnstrueiffvaluebegins withprefix.
-
Method Details
-
equals
public static boolean equals(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef target) Returnstrueiff the two byte sequences have identical length and content. Equivalent toBytesRef.bytesEquals(BytesRef)but routed throughArrays.equals(byte[], int, int, byte[], int, int)so it picks up the JDK's vectorized intrinsic on hot paths. -
startsWith
public static boolean startsWith(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef prefix) Returnstrueiffvaluebegins withprefix. An empty prefix matches every value (including an empty one). Returnsfalsewhenprefixis longer thanvalue. -
endsWith
public static boolean endsWith(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef suffix) Returnstrueiffvalueends withsuffix. An empty suffix matches every value (including an empty one). Returnsfalsewhensuffixis longer thanvalue. -
containsLiteral
public static boolean containsLiteral(org.apache.lucene.util.BytesRef value, org.apache.lucene.util.BytesRef literal) Returnstrueiffvaluecontainsliteralas a contiguous subsequence. An empty literal matches every value (including an empty one). Routes through the SIMD substring search exposed byBinaryDocValuesContainsTermQuery.contains(byte[], int, int, BytesRef).The Lucene query class is used purely as a static-method shim around
ESVectorUtil#contains:simdvec's module exports the SIMD utility only toorg.elasticsearch.server, so plugins (unnamed modules) cannot import it directly. Calling it through this server-side neighbor keeps the SIMD intent without forcing every consumer plugin to add asimdvecdependency it cannot legally use at runtime. If the shim ever moves to a more semantically-named:serverhome, only this method needs to change. -
affixContains
public static boolean affixContains(org.apache.lucene.util.BytesRef value, @Nullable org.apache.lucene.util.BytesRef prefix, @Nullable org.apache.lucene.util.BytesRef literal, @Nullable org.apache.lucene.util.BytesRef suffix) Composite predicate: returnstrueiffvaluestarts withprefix, ends withsuffix, and containsliteralas a contiguous subsequence anywhere between the matched prefix and suffix. Any of the three components may benullor empty, in which case the corresponding check is skipped.This implements the SQL
LIKE 'prefix%literal%suffix'family in a single pass:prefix*→(prefix, null, null)*suffix→(null, null, suffix)*literal*→(null, literal, null)prefix*suffix→(prefix, null, suffix)prefix*literal*→(prefix, literal, null)*literal*suffix→(null, literal, suffix)prefix*literal*suffix→(prefix, literal, suffix)
The order of checks is prefix → suffix → literal: the affix checks are short JDK- intrinsified equality comparisons (typically ≤ 32 bytes) and reject the bulk of non-matching values cheaply, leaving the more expensive SIMD substring scan for survivors. For correctness, the literal scan is restricted to the bytes strictly between the prefix and suffix regions: this prevents the literal from straddling and double-counting either affix region (e.g.
value="aXa",prefix="a",literal="aXa",suffix="a"must match iffaXaappears in the empty middle slice — which it does not — not iff it appears anywhere in the full value).A single combined-length guard rejects any value that cannot host all three components end-to-end without overlap: when
prefix.length + literal.length + suffix.length > value.lengththe predicate returnsfalseimmediately. This subsumes both the "affixes don't fit" case (literal length zero) and the "literal can't fit between the affixes" case, and it matches the non-overlapping-concatenation semantics thatByteRunAutomatonuses on the same patterns — the parity callers depend on.When all three components are absent (every parameter
nullor empty) this returnstrueunconditionally — the vacuum predicate. Callers typically partition that case upstream as amatchesAllfast path; reaching this method with all-null arguments is harmless but wasteful.
-