Advanced Query Techniques with Easysearch Java Client 2.0.x

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.

  1. 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.
  1. 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.
  1. 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.

Tags: Easysearch java-sdk boolean-query QueryString constant-score

Posted on Fri, 30 Oct 2026 16:13:27 +0000 by jheitz