This guide explores the implementation of sophisticated search capabilities using the Easysearch Java Client 2.0.x, focusing on constructing and executing different query types efficiently.
- QueryString Query: Flexible Full-Text Search
The QueryString query type enables developers to perform full-text searches using a syntax similar to the native query language. Its particularly useful for parsing unstructured user input that may contain logical operators or wildcards.
Core Parameters
fields: Target fields for the search.query: The search string containing operators like AND, OR, or NOT.default_operator: Fallback logical operator when none is specified in the string.analyze_wildcard: Determines whether wildcard patterns undergo analysis.
Implementation Examples
Approach A: JSON Deserialization
@Test
public void executeQueryStringViaJson() {
String rawPayload = "{" +
" \"query_string\": {" +
" \"fields\": [\"document_title\", \"body_text\"]," +
" \"query\": \"easysearch && java-sdk\"," +
" \"default_operator\": \"AND\"," +
" \"analyze_wildcard\": true" +
" }" +
"}";
try (StringReader reader = new StringReader(rawPayload)) {
JacksonJsonpMapper jsonMapper = new JacksonJsonpMapper();
JsonParser jsonParser = jsonMapper.jsonProvider().createParser(reader);
Query parsedRequest = Query._DESERIALIZER.deserialize(jsonParser, jsonMapper);
QueryStringQuery targetClause = parsedRequest.queryString();
Query finalQuery = Query.of(builder -> builder.queryString(targetClause));
System.out.println(finalQuery);
} catch (Exception e) {
e.printStackTrace();
}
}
Recommended Scenarios
- Processing raw search bars where users type logical expressions.
- Multi-field full-text scanning with out rigid structure.
- Situations requiring wildcard or fuzzy matching on user input.
- Boolean Query: Orchestrating Complex Search Logic
The Bool query serves as a compound container that merges multiple sub-queries using Boolean logic. It is the backbone for implementing sophisticated filtering and scoring mechanisms.
Sub-Clause Behavior
| Clause | Functionality |
|---|---|
must |
Enforces strict matching. Documents must satisfy all nested conditions. |
must_not |
Exclusion filter. Matches are strictly removed from the result set. |
should |
Optional matching. Increases relevance score when matched. Use minimum_should_match to enforce a baseline. |
filter |
Non-scoring context. Optimized for exact matches, ranges, or existence checks. Results are typically cached for performance. |
Implementation Examples
Method 1: JSON Payload Parsing
@Test
public void buildBoolViaJson() {
String jsonStructure = "{" +
" \"bool\": {" +
" \"must\": [{" +
" \"match\": { \"subject\": \"cloud-native\" }" +
" }]," +
" \"should\": [{" +
" \"term\": { \"category\": \"tutorial\" }" +
" }, {" +
" \"term\": { \"category\": \"guide\" }" +
" }]," +
" \"must_not\": [{" +
" \"term\": { \"visibility\": \"private\" }" +
" }]," +
" \"filter\": [{" +
" \"range\": { \"created_at\": { \"gte\": \"2023-01-01\" } }" +
" }]," +
" \"minimum_should_match\": 1" +
" }" +
"}";
JacksonJsonpMapper converter = new JacksonJsonpMapper();
try (StringReader input = new StringReader(jsonStructure)) {
Query intermediate = Query._DESERIALIZER.deserialize(
converter.jsonProvider().createParser(input), converter);
BoolQuery compound = intermediate.bool();
Query output = Query.of(b -> b.bool(compound));
System.out.println(output);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Method 2: Type-Safe Builder Pattern
@Test
public void constructBoolProgrammatically() {
BoolQuery.Builder compoundBuilder = new BoolQuery.Builder();
compoundBuilder.must(MatchQuery.of(m -> m.field("subject").query("cloud-native"))._toQuery());
compoundBuilder.should(TermQuery.of(t -> t.field("category").value("tutorial"))._toQuery());
compoundBuilder.should(TermQuery.of(t -> t.field("category").value("guide"))._toQuery());
compoundBuilder.mustNot(TermQuery.of(t -> t.field("visibility").value("private"))._toQuery());
compoundBuilder.filter(RangeQuery.of(r -> r.field("created_at").gte(JsonData.of("2023-01-01")))._toQuery());
compoundBuilder.minimumShouldMatch(1);
Query request = Query.of(q -> q.bool(compoundBuilder.build()));
System.out.println(request);
}
Recommended Scenarios
- Implementing enterprise search with mandatory filters and optional boosting.
- Combining full-text relevance with strict numeric or date constraints.
- Dynamically assembling search criteria based on UI toggles.
- Constant Score Query: Performance-Optimized Filtering
When relevance scoring is unnecessary or detrimental to performance, the ConstantScore query wraps a filter clause and assigns a uniform weight to every matching document. It bypasses TF/IDF calculations entirely.
Key Attributes
filter: The underlying query condition. All returning documents must satisfy it.boost: A static floating-point value applied to the score of matched documents. Defaults to 1.0.
Implementation Examples
Approach A: JSON String Conversion
@Test
public void parseConstantScoreJson() {
String rawJson = "{" +
" \"constant_score\": {" +
" \"filter\": {" +
" \"term\": { \"state\": \"active\" }" +
" }," +
" \"boost\": 1.5" +
" }" +
"}";
JacksonJsonpMapper deserializer = new JacksonJsonpMapper();
try (StringReader buffer = new StringReader(rawJson)) {
Query parsed = Query._DESERIALIZER.deserialize(deserializer.jsonProvider().createParser(buffer), deserializer);
ConstantScoreQuery target = parsed.constantScore();
Query payload = Query.of(b -> b.constantScore(target));
System.out.println(payload);
} catch (Exception e) {
e.printStackTrace();
}
}
Approach B: Fluent API Construction
@Test
public void buildConstantScoreWithBuilder() {
ConstantScoreQuery.Builder wrapper = new ConstantScoreQuery.Builder();
wrapper.filter(TermQuery.of(t -> t.field("state").value("active"))._toQuery());
wrapper.boost(1.5f);
Query finalQuery = Query.of(q -> q.constantScore(wrapper.build()));
System.out.println(finalQuery);
}
Recommended Scenarios
- Strict inclusion/exclusion rules where ranking order does not matter.
- High-throughput filtering operations benefiting from query caching.
- Overriding default scoring mechanisms with a fixed baseline.
- Embedding within larger Boolean structures as pre-filters.