Elasticsearch Java High Level REST 클라이언트에서 검색

63162 단어 JavaElasticsearchtech
이 문서는 로컬 개발 환경에서 다양한 질의에서 공식 Java 클라이언트(High Level REST Client)를 사용하여 읽어들입니다.
본고에서 사용한 코드는 아래 창고에서도 공개된다.
https://github.com/ryo-utsunomiya/elasticsearch-java

사용 중인 소프트웨어 버전


  • Elasticsearch 7.10.1

  • Kibana 7.10.1

  • Elasticsearch Java High Level REST Client 7.10.1
  • Java 11( AdoptOpenJDK 11.0.9.1)

  • Gradle 6.7.1

  • Docker 19.03.12
  • macOS 11.1
  • 환경 구성(생략)


    이 글은 환경 구축 절차를 생략하였다.아래 글에 기재된 환경에서 집행한다.
    https://zenn.dev/ryo511/articles/176ffe0571c3c7

    테스트 데이터 만들기


    Elasticsearch에 테스트 검색에 사용할 데이터를 등록합니다.다음은 키바나의 DevTools에서 발매할 수 있는 REST 팟캐스트 샘플.
    # my_index を削除(マッピングを作り直すため)
    DELETE /my_index
    
    # my_index を作成
    PUT /my_index
    
    # my_index のマッピング定義
    PUT /my_index/_mapping
    {
      "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "integer"
        },
        "favorite_genres": {
          "type": "keyword"
        }
      }
    }
    
    다음에 등록된 데이터.
    POST /my_index/_doc
    {
      "name": "John",
      "age": 40,
      "favorite_genres": ["rock", "r&b"]
    }
    
    POST /my_index/_doc
    {
      "name": "Paul",
      "age": 78,
      "favorite_genres": ["rock", "r&b", "pop"]
    }
    
    POST /my_index/_doc
    {
      "name": "George",
      "age": 58,
      "favorite_genres": ["rock", "r&b", "country", "funk", "jazz"]
    }
    
    POST /my_index/_doc
    {
      "name": "Richard",
      "age": 80,
      "favorite_genres": ["rock", "techno", "classic", "jazz"]
    }
    

    Search API 사용


    이어 Elasticsearch Java High Level REST Client를 사용하여 이 데이터베이스에 검색 쿼리를 던진다.
    문서는 다음을 참조하십시오.
    https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.10/java-rest-high-search.html

    모두 가져오기


    우선 모두 얻으려고 시도해 보자.
    GET /my_index/_search
    {
      "query": {
        "match_all": {}
      }
    }
    
    Java로 이렇게 씁니다.
    package esjava;
    
    import java.io.IOException;
    import java.util.Arrays;
    import org.apache.http.HttpHost;
    import org.elasticsearch.action.search.SearchRequest;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.builder.SearchSourceBuilder;
    
    public class App {
    
      public static void main(String[] args) {
        try (var client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http")))) {
    
          var request = new SearchRequest("my_index");
          request.source(
              SearchSourceBuilder.searchSource()
                  .query(QueryBuilders.matchAllQuery())
          );
          var response = client.search(request, RequestOptions.DEFAULT);
          Arrays.stream(response.getHits().getHits())
              .forEach(h -> System.out.println(h.getSourceAsString()));
    
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    }
    
    ./gradlew run 등으로 이 작업을 수행하면 다음과 같은 출력을 얻을 수 있습니다.
    {"name":"John","age":40,"favorite_genres":["rock","r&b"]}
    {"name":"Paul","age":78,"favorite_genres":["rock","r&b","pop"]}
    {"name":"George","age":58,"favorite_genres":["rock","r&b","country","funk","jazz"]}
    {"name":"Richard","age":80,"favorite_genres":["rock","techno","classic","jazz"]}
    

    가져올 필드 지정

    _source에서 가져올 필드를 지정합니다.
    GET /my_index/_search
    {
      "query": {
        "match_all": {}
      },
      "_source": ["name", "age"]
    }
    
    자바는 이렇다.
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.matchAllQuery())
        .fetchSource(new String[]{"name", "age"}, null)
    
    fetchSource()의 첫 번째 파라미터는include list이고, 두 번째 파라미터는exclude list이며, 그 중 하나만 지정하면 OK입니다.
    아래와 같이 지정된 필드만 얻을 수 있습니다.
    {"name":"John","age":40}
    {"name":"Paul","age":78}
    {"name":"George","age":58}
    {"name":"Richard","age":80}
    

    붙이다


    from/size를 지정하면 얻을 위치를 지정할 수 있습니다.from은 0으로 시작합니다.
    GET /my_index/_search
    {
      "query": {
        "match_all": {}
      },
      "_source": ["name", "age"],
      "from": 1,
      "size": 2
    }
    
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.matchAllQuery())
        .fetchSource(new String[]{"name", "age"}, null)
        .from(1)
        .size(2)
    
    John이 날아갔고 폴과 조지는 두 건을 이미 취득했다.
    {"name":"Paul","age":78}
    {"name":"George","age":58}
    

    정렬


    정렬에 사용할 필드와 오름차순/내림차순을 지정합니다.
    GET /my_index/_search
    {
      "query": {
        "match_all": {}
      },
      "_source": ["name", "age"],
      "sort": [
        {
          "age": {
            "order": "asc"
          }
        }
      ]
    }
    
    나이가 어린 순서로 배열한다.
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.matchAllQuery())
        .fetchSource(new String[]{"name", "age"}, null)
        .sort("age", SortOrder.ASC)
    

    match 질의


    match 조회에서text 형식의 필드에 대해 전문 검색을 할 수 있습니다.또한 빈 구분자로 여러 검색 키워드를 지정할 수도 있습니다(기본값은 OR 조건).
    {"name":"John","age":40}
    {"name":"George","age":58}
    {"name":"Paul","age":78}
    {"name":"Richard","age":80}
    
    GET /my_index/_search
    {
      "query": {
        "match": {
          "name": "john paul"
        }
      },
      "_source": ["name", "age"]
    }
    
    존과 폴 2건을 취득했다.
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.matchQuery("name", "john paul"))
        .fetchSource(new String[]{"name", "age"}, null)
    
    여러 키워드를 AND 조건으로 설정하려면 operator를 지정합니다.
    {"name":"John","age":40}
    {"name":"Paul","age":78}
    
    GET /my_index/_search
    {
      "query": {
        "match": {
          "name": {
            "query": "john paul",
            "operator": "and"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    는 이 조건에 맞는 문서가 존재하지 않기 때문에 결과를 0건으로 얻었습니다.

    term 질의


    term 검색에서 키워드 형식의 필드와 완전히 일치할 수 있습니다.
    SearchSourceBuilder.searchSource()
        .query(
            QueryBuilders.matchQuery("name", "john paul")
                .operator(Operator.AND)
        )
        .fetchSource(new String[]{"name", "age"}, null)
    
    GET /my_index/_search
    {
      "query": {
        "term": {
          "favorite_genres":  "r&b"
        }
      },
      "_source": ["name", "favorite_genres"]
    }
    
    favorite_genres에 r&b가 포함된 문서만 가져옵니다.
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.termQuery("favorite_genres", "r&b"))
        .fetchSource(new String[]{"name", "favorite_genres"}, null)
    

    terms 질의


    여러 키워드를 지정하려면terms 조회를 사용하십시오.
    {"favorite_genres":["rock","r&b"],"name":"John"}
    {"favorite_genres":["rock","r&b","pop"],"name":"Paul"}
    {"favorite_genres":["rock","r&b","country","funk","jazz"],"name":"George"}
    
    GET /my_index/_search
    {
      "query": {
        "terms": {
          "favorite_genres": ["pop", "techno"]
        }
      },
      "_source": ["name", "favorite_genres"]
    }
    
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.termsQuery("favorite_genres", "pop", "techno"))
        .fetchSource(new String[]{"name", "favorite_genres"}, null)
    

    range 쿼리


    range 조회를 사용하여 숫자 형식이나 날짜 형식의 범위를 지정합니다.
    {"favorite_genres":["rock","r&b","pop"],"name":"Paul"}
    {"favorite_genres":["rock","techno","classic","jazz"],"name":"Richard"}
    
    GET /my_index/_search
    {
      "query": {
        "range": {
          "age": {
            "gt": 40,
            "lt": 80
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    나이가 40보다 많으면 80보다 작은 문서를 얻을 수 있다.
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.rangeQuery("age").gt(40).lt(80))
        .fetchSource(new String[]{"name", "age"}, null)
    
    이상/이하 검색은 gte/lte를 사용합니다.
    {"name":"Paul","age":78}
    {"name":"George","age":58}
    
    SearchSourceBuilder.searchSource()
        .query(QueryBuilders.rangeQuery("age").gte(40).lte(80))
        .fetchSource(new String[]{"name", "age"}, null)
    

    여러 검색 조건 조합(bool 쿼리)


    이전에 소개한 검색어를 조합해서 사용하는 것은 bool 검색이다.예를 들어 다음과 같은 조건을 만족하는 사용자를 얻으려고 한다.
  • 필수: 록을 좋아하고 50세 이상
  • 그중 하나를 만족시키면 OK:r&b가 좋아하거나 팝이 좋아한다
  • NG: 테크노
  • 이것은must/should/mustnot/filter를 사용하면 다음과 같은 내용을 쓸 수 있습니다.
    {"name":"John","age":40}
    {"name":"Paul","age":78}
    {"name":"George","age":58}
    {"name":"Richard","age":80}
    
    GET /my_index/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "favorite_genres": "rock"
              }
            }
          ],
          "should": [
            {
              "term": {
                "favorite_genres": "r&b"
              }
            },
            {
              "term": {
                "favorite_genres": "pop"
              }
            }
          ],
          "must_not": [
            {
              "term": {
                "favorite_genres": "techno"
              }
            }
          ],
          "filter": {
            "range": {
              "age": {
                "gte": 50
              }
            }
          }
        }
      }
    }
    
    는 아래 2건을 취득할 수 있다.
    SearchSourceBuilder.searchSource()
        .query(
            QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("favorite_genres", "rock"))
                .should(QueryBuilders.termQuery("favorite_genres", "r&b"))
                .should(QueryBuilders.termQuery("favorite_genres", "pop"))
                .mustNot(QueryBuilders.termQuery("favorite_genres", "techno"))
                .filter(QueryBuilders.rangeQuery("age").gte(50))
        )
    

    매듭을 짓다


    Elasticsearch Java High Level REST 클라이언트를 사용하여 기본 검색을 수행하는 방법에 대해 설명했습니다.
    이 글에는 소개되지 않은 조회(match phrase 등)와 기능(정렬에 사용된 점수를 조정하는 계산 방법) 등도 있으니 더욱 응용된 사용 방법은 공식 문서를 참조하시기 바랍니다.
    https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.10/java-rest-high-search.html

    좋은 웹페이지 즐겨찾기