ElasticSearch DSL & Java RestHighLevelClient: Complete Operations Guide

This tutorial demonstrates how to perform ElasticSearch index, document, query, and aggregation operations using both DSL queries and Java RestHighLevelClient within a SpringBoot project, covering setup, CRUD, search types, sorting, pagination, highlighting, and nested aggregations with code examples.

Java Captain
Java Captain
Java Captain
ElasticSearch DSL & Java RestHighLevelClient: Complete Operations Guide

Project Setup

A SpringBoot project is created with the following structure: ElasticSearchConfig configures the RestHighLevelClient bean, MyHotel entity maps the index structure, DSL files store common queries, and JSON files hold request payloads. Four test classes cover index, document, search, and aggregation operations.

Project structure diagram
Project structure diagram

Maven Dependencies

The pom.xml declares elasticsearch-rest-high-level-client and overrides the ElasticSearch version to 7.14.2 via elasticsearch.version property because RestHighLevelClient was deprecated starting from 7.15. Other dependencies include Lombok, FastJSON, Commons Lang3, and Spring Boot test starter.

<properties>
  <maven.compiler.source>8</maven.compiler.source>
  <maven.compiler.target>8</maven.compiler.target>
  <elasticsearch.version>7.14.2</elasticsearch.version>
</properties>
<dependencies>
  <dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.8</version>
  </dependency>
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

ElasticSearch Configuration

Custom connection properties are defined in application.yml:

elasticsearch:
  username: elastic
  password: tdGiSi*fhwW0F60*i*Jc
  urls: [http://192.168.136.128:9200]
ElasticSearchConfig

reads these properties, builds an HttpHost array, configures basic authentication, and adds a compatibility header application/vnd.elasticsearch+json;compatible-with=7 to avoid errors when operating against ElasticSearch 8.x with the 7.x client.

@Configuration
public class ElasticSearchConfig {
  @Value("${elasticsearch.username}")
  private String username;
  @Value("${elasticsearch.password}")
  private String password;
  @Value("${elasticsearch.urls}")
  private String[] urls;

  @Bean
  public RestHighLevelClient restHighLevelClient() {
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(AuthScope.ANY,
        new UsernamePasswordCredentials(username, password));
    ArrayList<HttpHost> hostlist = new ArrayList<>();
    for (String url : urls) {
      hostlist.add(HttpHost.create(url));
    }
    HttpHost[] hosts = hostlist.toArray(new HttpHost[0]);
    RestClientBuilder builder = RestClient.builder(hosts);
    builder.setHttpClientConfigCallback(httpClientBuilder ->
        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
    builder.setDefaultHeaders(new Header[]{
        new BasicHeader(HttpHeaders.ACCEPT,
            "application/vnd.elasticsearch+json;compatible-with=7"),
        new BasicHeader(HttpHeaders.CONTENT_TYPE,
            "application/vnd.elasticsearch+json;compatible-with=7")
    });
    return new RestHighLevelClient(builder);
  }
}

MyHotel Entity

Simple POJO with Lombok @Data holding hotel fields: id, name, address, price, brand, city, location (geo_point), and distance (for sorting results).

@Data
public class MyHotel {
  private Integer id;
  private String name;
  private String address;
  private Integer price;
  private String brand;
  private String city;
  private String location;
  private Double distance;
}

Index Operations

DSL statements are stored in IndexDSL.txt; Java tests in IndexTest.

DSL Examples

Create index with mappings: id (keyword), name (text, ik_max_word analyzer, copy_to "all"), address (keyword, index:false), price (integer), brand (keyword, copy_to "all"), city (keyword), location (geo_point), all (text, ik_max_word).

Get index : GET /myhotel Add field (only addition allowed after creation): PUT /myhotel/_mapping with addScore (integer, index:false).

Delete index :

DELETE /myhotel

Java Implementation

Uses CreateIndexRequest, GetIndexRequest, PutMappingRequest, DeleteIndexRequest. JSON payloads are read from classpath resources ( JSON/CreateMyHotelJson.txt, JSON/UpdateMyHotelJson.txt) via ResourceUtils and BufferedReader. The exists method returns boolean; get prints mappings as pretty JSON using FastJSON.

@Test
void createIndexTest() throws IOException {
  CreateIndexRequest request = new CreateIndexRequest("myhotel");
  File file = ResourceUtils.getFile("classpath:JSON/CreateMyHotelJson.txt");
  String createJson;
  try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    createJson = br.readLine();
  }
  request.source(createJson, XContentType.JSON);
  client.indices().create(request, RequestOptions.DEFAULT);
}

Document Operations

DSL in DocDSL.txt; Java in DocTest.

DSL Examples

Add/Full update : POST /myhotel/_doc/1 or PUT /myhotel/_doc/1 with full JSON document.

Get by ID : GET /myhotel/_doc/1 Partial update : POST /myhotel/_update/1 with doc containing changed fields.

Delete :

DELETE /myhotel/_doc/1

Java Implementation

addDocTest

: reads JSON, extracts id, builds IndexRequest. getDocByIdTest: uses GetRequest, prints source JSON and deserializes to MyHotel. updateDocPartTest: UpdateRequest with request.doc("name", "new name", "price", "666"). deleteDocTest: DeleteRequest. bulkRequestTest: reads lines from DemoJsonData.txt, adds each as IndexRequest to BulkRequest, executes once.

@Test
void bulkRequestTest() throws IOException {
  File file = ResourceUtils.getFile("classpath:JSON/DemoJsonData.txt");
  BulkRequest request = new BulkRequest();
  try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String json = br.readLine();
    while (StringUtils.isNotBlank(json)) {
      JSONObject jsonObj = JSON.parseObject(json);
      request.add(new IndexRequest("myhotel")
          .id(jsonObj.getString("id"))
          .source(json, XContentType.JSON));
      json = br.readLine();
    }
  }
  client.bulk(request, RequestOptions.DEFAULT);
}

Document Queries

DSL in SearchDSL.txt; Java in SearchTest.

Query Types & DSL

Match All : { "query": { "match_all": {} } } Single Field (match) : queries the all field (copy_to target) for "朝阳如家".

Multi-field (multi_match) : searches "朝阳如家" across brand and name; note: multi_match degrades performance, prefer copy_to.

Term (exact) : term on city for "北京".

Range : price between 100 and 300 ( gte / lte).

Bool Combination : must (match name "如家"), must_not (price > 400), filter (geo_distance 5km from 31.21,121.5). must and should affect scoring; filter and must_not do not.

Geo Distance Query : standalone geo_distance for 5km radius.

Function Score : base query (match "朝阳" on all), filter function boosting brand "速8" by weight 10, boost_mode=sum.

Sorting : by price asc then id asc; or by _geo_distance from a point (lat 31.034661, lon 121.612282) with unit km.

Pagination : from=20, size=10 with sort.

Highlighting : match on all for "北广场", highlight name with require_field_match=false because query field differs from highlight field.

Java Implementation Highlights

All tests use SearchRequest with QueryBuilders (matchAllQuery, matchQuery, multiMatchQuery, termQuery, rangeQuery, boolQuery, geoDistanceQuery, functionScoreQuery). boolTest demonstrates combining must (term on city) and filter (range on price). sortAndPageTest calculates from = (page-1)*size. matchDistanceTest uses GeoPoint and SortBuilders.geoDistanceSort with DistanceUnit.KILOMETERS. funcTest builds FunctionScoreQueryBuilder with FilterFunctionBuilder and ScoreFunctionBuilders.weightFactorFunction(10), sets boostMode(CombineFunction.SUM). Comment warns: if explicit sort is added, scoring is disabled. highlightTest sets HighlightBuilder().field("name").requireFieldMatch(false).

Common processResponse method extracts total hits, iterates SearchHit, deserializes to MyHotel, handles highlight fragments (replaces name), and reads sort values for distance.

@Test
void funcTest() throws IOException {
  SearchRequest request = new SearchRequest("myhotel");
  BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
  boolQuery.must(QueryBuilders.termQuery("city", "上海"));
  boolQuery.filter(QueryBuilders.rangeQuery("price").gte(200).lte(600));
  FunctionScoreQueryBuilder functionScoreQuery =
      QueryBuilders.functionScoreQuery(boolQuery,
          new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
              new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                  QueryBuilders.termQuery("brand", "速8"),
                  ScoreFunctionBuilders.weightFactorFunction(10))
          })
      .boostMode(CombineFunction.SUM);
  request.source().query(functionScoreQuery);
  SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  processResponse(response);
}

Aggregation Queries

DSL in AggDSL.txt; Java in AggTest.

DSL Examples

Terms Aggregation : group by brand, size 20, default descending count. Can set order: { "_count": "asc" } for ascending.

Filtered Aggregation : first query price lte 200, then aggregate on brand.

Nested Aggregation (stats) : under each brand bucket, compute stats on price (min, max, sum, avg). Order by priceAgg.min asc.

Alternative Nested Aggregation : separate min, max, sum, avg sub-aggregations for selective retrieval.

Java Implementation

aggTest

: range query price 200-500, size=0, terms aggregation on brand size 10. Parses buckets, prints brand and docCount. aggStatsTest: same query, terms aggregation with order(BucketOrder.aggregation("priceAgg.min", true)), sub-aggregation stats("priceAgg") on price. Retrieves Stats object for min/max/sum/avg as strings. aggregationTest: identical logic but uses individual MinAggregationBuilder, MaxAggregationBuilder, SumAggregationBuilder, AvgAggregationBuilder added as sub-aggregations. Retrieves each via bucket's aggregations map.

@Test
void aggStatsTest() throws IOException {
  SearchRequest request = new SearchRequest("myhotel");
  request.source().query(QueryBuilders.rangeQuery("price").gte(200).lte(500));
  request.source().size(0);
  TermsAggregationBuilder termsAggregationBuilder =
      AggregationBuilders.terms("brandAgg").field("brand")
          .order(BucketOrder.aggregation("priceAgg.min", true))
          .subAggregation(AggregationBuilders.stats("priceAgg").field("price"));
  request.source().aggregation(termsAggregationBuilder);
  SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  Aggregations aggregations = response.getAggregations();
  Terms brandAgg = aggregations.get("brandAgg");
  for (Terms.Bucket bucket : brandAgg.getBuckets()) {
    String brandName = bucket.getKeyAsString();
    long docCount = bucket.getDocCount();
    Stats priceAgg = bucket.getAggregations().get("priceAgg");
    System.out.println("brand: " + brandName + ", count: " + docCount +
        ", min: " + priceAgg.getMinAsString() +
        ", max: " + priceAgg.getMaxAsString() +
        ", sum: " + priceAgg.getSumAsString() +
        ", avg: " + priceAgg.getAvgAsString());
  }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaDSLElasticSearchSpringBootHighlightingGeo-distanceSearch QueriesRestHighLevelClientAggregationsIndex OperationsDocument Operations
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.