エキサイト株式会社 メディア事業部エンジニアの中尾です。
rest-high-level-clientのようなライブラリではなく、restTmeplateでElasticsearchに問い合わせる方法を説明します。
https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client
使う場面として、Elasticsearch5系のバージョン以下の場合、Elasticsearchで使っているオプションがライブラリで扱われていない(auto_generate_synonyms_phrase_query)などあるので、
DAOとして、以下のようにJsonのNodeを渡します。
@Component @RequiredArgsConstructor public class ElasticSearchDaoImpl implements ElasticsearchDao { @Value("${spring.elasticsearch.url}") public String url; private final RestTemplate restTemplate; private final ObjectMapper objectMapper; @Override public JsonNode searchRequest(JsonNode jsonNode) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> entity = new HttpEntity<String>(jsonNode.toString(), headers); ResponseEntity<String> exchange = restTemplate.exchange(this.url, HttpMethod.POST, entity, String.class); if (exchange.getStatusCode() != HttpStatus.OK) { throw new ElasticsearchException(exchange.getBody()); } try { return objectMapper.readTree(exchange.getBody()); } catch (JsonProcessingException e) { throw new ElasticsearchException(e.getMessage()); } } }
どんなJsonNodeを渡すかというと、以下のようにElasticsearchに問い合わせるのに必要そうな値をセットするデータクラスを用意し、SearchSourceBuilder.toStringでstringにした後、objectMapperでJsonNode化します。
JsonNode jsonNode = objectMapper.readTree(elasticSearchForm.toString());
@Data @Accessors(chain = true) public class ElasticSearchForm { /** * Elasticsearchから取得するインデックス */ private String index; /** * Elasticsearchから取得するカラム */ private String[] includes; /** * Elasticsearchから取得しないカラム */ private String[] excludes; /** * 検索条件 */ private BoolQueryBuilder boolQueryBuilder; /** * offset */ private int from = 0; /** * limit */ private int size = 10; /** * order */ private FieldSortBuilder fieldSortBuilder; public String toString(){ return new SearchSourceBuilder() .fetchSource( includes, excludes) .query(boolQueryBuilder) .from(from) .size(size) .sort(fieldSortBuilder) .toString(); } }
JsonNode化すれば、不要なところは以下のように消すことができます。
※本当はもっとネストしていると思いますが、簡略しています
((ObjectNode) jsonNode.get("query").........remove("auto_generate_synonyms_phrase_query");
あとは、このJsonNodeを先程のDAOの引数に入れるだけです。
レスポンスについて、以下のようにstreamを使えば、必要なデータのListが作れると思います。 他に必要なデータは適宜JsonNodeから取得してください。
StreamSupport.stream( response.get("hits").get("hits").spliterator(), false) ).map(e -> { // 処理 } ) .collect(Collectors.toList());
Elasticsearchに問い合わせるJsonはネストが深く、文字列結合やMapだとどうしても見通しが悪くなる場合があります。
Builderを使えるところは使って、それをjsonに変換した方が見通しがよくなると思うので、よかったら使ってください。