엘라스틱서치 7.0에서 Tranport 클라이언트 모듈은 미지원되고 8.0에서는 모두 제거될 예정
Transport 클라이언트 연결
dependencies {
compile group: 'org.elasticsearch.client', name: 'transport', version: '6.4.3'
}
Settings settings = Settings.builder()
.put("cluster.name", "javacafe-es")
//.put("client.transport.sniff", true)
.build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
- Transport 클라이언트는 내부적으로 소켓을 사용해 엘라스틱서치 클러스터에 원격으로 연결(Setting 정보에 클러스터 입력)
- Port와 IP 정보를 입력해야 하며 Port값이 없다면 기본적으로 9300 Port를 사용
- Transport는 새로운 노드를 추가하거나, 기존 노드를 삭제할 수 있는 스니핑이 내장되어 있음
- 스니핑 기능이 활성화되면 addTransportAddress 메서드를 호출해서 빌드된 노드 목록을 5초에 한 번씩 갱신
매핑 API 사용하기
동작 Query
PUT movie_java
{
"settings": {
"index": {
"number_of_shards": 3,
"number_of_replicas": 1
}
},
"mappings": {
"_doc": {
"properties": {
"movieCd": {
"type": "keyword",
"store": true
},
"movieNm": {
"type": "text",
"store": true,
"index_options": "docs"
},
"movieNmEn": {
"type": "text",
"store": true,
"index_options": "docs"
}
}
}
}
}
인덱스 생성(Indice API)
String INDEX_NAME = "movie_java";
String TYPE_NAME = "_doc"; // ES 6.x까지는 type 사용 가능, 7.x부터는 제거됨
// 매핑 정보 작성
XContentBuilder indexBuilder = jsonBuilder()
.startObject()
.startObject("properties")
.startObject("movieId")
.field("type", "keyword")
.field("store", true)
.field("index_options", "docs")
.endObject()
.startObject("movieNm")
.field("type", "text")
.field("store", true)
.field("index_options", "docs")
.endObject()
.startObject("movieNmEn")
.field("type", "text")
.field("store", true)
.field("index_options", "docs")
.endObject()
.endObject()
.endObject();
client.admin().indices().prepareCreate(INDEX_NAME)
.setSettings(Settings.builder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 1)
)
.addMapping(TYPE_NAME, indexBuilder)
.get();
- 모든 항목은 startObject(), endObject() 메서드로 표현해야 한다.
- 필드의 타입이나 속성을 지정할 경우 field() 메서드를 사용하고, 인덱스를 생성할 때는 client(), admin(), indices() 메서드를 사용한다.
- prepareCreate() 메서드를 이용해 생성한 인덱스의 이름을 지정하고, 설정 정보와 인덱스 정보를 설정
- 모든 설정이 완료되면 get() 메서드를 호출하면 된다
- get() 호출 시, 엘라스틱서치로 매핑 정보를 전송하고 인덱스 생성 여부를 결과로 반환
문서 API 사용하기
단건 문서 추가
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc";
String _id = "1";
// 문서 색인
IndexResponse response = client.prepareIndex(INDEX_NAME, TYPE_NAME, _id)
.setSource(jsonBuilder()
.startObject()
.field("movieId", "20173732")
.field("movieNm", "살아남은 아이")
.field("movieNmEn", "Last Child")
.endObject()
)
.get();
- 필드명과 필드값을 지정해서 생성 후 setSource() 메서드에 설정하면 된다.
- prepareIndex() 메서드에 인덱스 명과 타입명, 데이터의 _id를 직접 입력해서 문서를 추가한다.
- _id 값이 없으면 UUID로 값이 대체됨
대량의 문서 추가
// 인덱스 / 타입명
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc"; // ES 6.x까지 사용
// 여러 개의 데이터를 담을 리스트
List<XContentBuilder> contentBuilders = new ArrayList<>();
// 1번 데이터 추가
XContentBuilder builder = jsonBuilder()
.startObject()
.field("movieId", "20184623")
.field("movieNm", "바람 난 아내들 2")
.field("movieNmEn", "")
.endObject();
contentBuilders.add(builder);
// 2번 데이터 추가
builder = jsonBuilder()
.startObject()
.field("movieId", "20174244")
.field("movieNm", "버블 패밀리")
.field("movieNmEn", "Family in the Bubble")
.endObject();
contentBuilders.add(builder);
// BulkRequestBuilder 객체 생성
BulkRequestBuilder bulkRequest = client.prepareBulk();
// contentBuilders 리스트 순회하며 문서 추가
int idCounter = 1;
for (XContentBuilder xContentBuilder : contentBuilders) {
bulkRequest.add(
client.prepareIndex(INDEX_NAME, TYPE_NAME, String.valueOf(idCounter++))
.setSource(xContentBuilder)
);
}
// 문서 전송
BulkResponse bulkResponse = bulkRequest.get();
- 다수의 데이터를 추가할 때 _bluk API를 이용하며, bulkRequestBuilder로 데이터를 저장한다.
- 색인 요청 후 결과를 확인하려면 IndexResponse 또는 BulkResponse 객체로 전달받으면 된다.
- IndexResponse: _index, _type, _id, _version, _status, _shards, result 정보도 받을 수 있음
- BulkResponse: 단순 작업 실패 여부만 확인 가능
문서 조회
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc"; // ES 6.x까지는 type 사용 가능
String _id = "20184623";
// 단일 문서 조회
GetResponse response = client.prepareGet(INDEX_NAME, TYPE_NAME, _id).get();
- _id 기반으로 인덱스의 문서를 질의할 때 사용
- prepareGet() 메서드를 이용하며 결과로 해당 id를 가지는 문서가 반환된다.
- 결과로 제공되는 GetResponse 객체에서 response.getSource()를 호출해 Map 형태로 객체가 제공
문서 삭제
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc";
// 단일 문서 삭제
String _id = "20184623";
DeleteResponse response = client.prepareDelete(INDEX_NAME, TYPE_NAME, _id).get();
//다건 문서 삭제
BulkByScrollResponse bulkResponse = DeleteByQueryAction.INSTANCE
.newRequestBuilder(client)
.filter(QueryBuilders.matchQuery("movieNm", "바람 난 아내들 2"))
.source(INDEX_NAME)
.get();
- prepareDelete() 메서드를 이용해 id에 해당하는 문서를 삭제할 수 있다.
- Query 기반으로 특정 문서를 검색해서 삭제할 수 있다.
문서 업데이트
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc";
String _id = "20174244";
// UpdateRequest 생성
UpdateRequest updateRequest = new UpdateRequest(INDEX_NAME, TYPE_NAME, _id)
.doc(jsonBuilder()
.startObject()
.field("movieNm", "수정 문서")
.endObject()
);
// 문서 수정 실행
UpdateResponse updateResponse = client.update(updateRequest).get();
- 문서를 업데이트할 때 update() 메서드를 사용
한 번에 다수의 문서 조회
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc"; // ES 6.x까지 사용
// MultiGet 요청
MultiGetResponse multiGetItemResponses = client.prepareMultiGet()
.add(INDEX_NAME, TYPE_NAME, "20184623")
.add(INDEX_NAME, TYPE_NAME, "20174244")
.get();
// 결과 확인
for (MultiGetItemResponse itemResponse : multiGetItemResponses) {
GetResponse response = itemResponse.getResponse();
if (response.isExists()) {
String json = response.getSourceAsString();
}
}
- _mget API로 엘라스틱 서치에 여러 번 요청할 내용을 한 번에 요청할 수 있다.
- prepareMultiGet() 메서드를 이용해 검색할 문서를 등록해서 한 번에 호출
Bulk Processor
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc"; // ES 6.x까지 사용
// BulkProcessor 생성
BulkProcessor bulkProcessor = BulkProcessor.builder(
client,
new BulkProcessor.Listener() {
@Override
public void beforeBulk(long executionId, BulkRequest request) {
System.out.println("Before bulk: " + request.numberOfActions() + " actions");
}
@Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
System.out.println("After bulk: " + response.getItems().length + " items");
}
@Override
public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
System.err.println("Bulk failed: " + failure.getMessage());
}
})
.setBulkActions(1000)
.setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
.setConcurrentRequests(1)
.build();
// 벌크 데이터 추가
bulkProcessor.add(new IndexRequest(INDEX_NAME, TYPE_NAME, "20184623")
.source(jsonBuilder()
.startObject()
.field("movieId", "20184623")
.field("movieNm", "바람 난 아내들 ?")
.field("movieNmEn", "")
.endObject()
));
bulkProcessor.add(new IndexRequest(INDEX_NAME, TYPE_NAME, "20174244")
.source(jsonBuilder()
.startObject()
.field("movieId", "20174244")
.field("movieNm", "버블 패밀리")
.field("movieNmEn", "Family in the Bubble")
.endObject()
));
- 한번에 처리할 문서 수, 문서 처리 방법, 데이터 새로고침 주기를 설정할 수 있는 인터페이스를 제공한다.
- 데이터양에 상관없이 지정한 조건에 만족하면 엘라스틱서치로 색인 요청을 보내는 방식으로 동작
검색 API 사용하기
search API
String INDEX_NAME1 = "movie_auto";
String INDEX_NAME2 = "movie_search";
String TYPE_NAME = "_doc"; // ES 6.x까지 사용
String FIELD_NAME = "movieId";
String QUERY = "20184623";
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME1, INDEX_NAME2)
.setTypes(TYPE_NAME)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.termQuery(FIELD_NAME, QUERY))
.setFrom(0)
.setSize(10)
.setExplain(true)
.get();
- setQuery() 메서드에 원하는 쿼리를 작성해 검색 요청을 할 수 있다.
scroll Api
String INDEX_NAME = "movie_search";
String FIELD_NAME = "movieNm";
String QUERY = "아내들";
// Term 쿼리 생성
QueryBuilder queryBuilder = QueryBuilders.termQuery(FIELD_NAME, QUERY);
// 최초 검색 실행 (Scroll 시작)
SearchResponse scrollResp = client.prepareSearch(INDEX_NAME)
.addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)
.setScroll(new TimeValue(60000)) // Scroll 타임아웃 60초
.setQuery(queryBuilder)
.setSize(30) // 한번에 가져올 문서 수
.get();
// Scroll 반복
do {
// 데이터 출력
for (SearchHit hit : scrollResp.getHits().getHits()) {
String movieNm = hit.getSourceAsMap().get("movieNm").toString();
System.out.println("movieNm: " + movieNm);
}
// 다음 Scroll batch 가져오기
scrollResp = client.prepareSearchScroll(scrollResp.getScrollId())
.setScroll(new TimeValue(60000))
.get();
} while (scrollResp.getHits().getHits().length != 0); // 더 이상 문서가 없을 때 종료
- 요청할 때마다 순차적으로 다음 페이지를 제공하는 Scroll API를 제공한다
- Scroll API는 첫 페이지를 호출할 때 scroll_id를 전달받아 초기에 설정한 사이즈로 지속적 데이터를 전송한다.
집계 API 사용하기
String INDEX_NAME = "movie_search";
String TYPE_NAME = "_doc"; // ES 6.x까지 사용
String FIELD_NAME = "repNationNm";
String QUERY = "한국";
String AGGREGATION_NAME = "countNationNm";
String AGGREGATION_FIELD = "typeNm";
// Terms Aggregation 생성
AggregationBuilder aggs = AggregationBuilders
.terms(AGGREGATION_NAME)
.field(AGGREGATION_FIELD)
.size(100);
// 검색 + Aggregation 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setTypes(TYPE_NAME)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.termQuery(FIELD_NAME, QUERY))
.addAggregation(aggs)
.setSize(0) // 검색 결과는 필요 없고 Aggregation만 가져오기
.get();
// Aggregation 결과 출력
Terms termBucket = response.getAggregations().get(AGGREGATION_NAME);
for (Terms.Bucket bucket : termBucket.getBuckets()) {
String typeNm = bucket.getKeyAsString();
long docCount = bucket.getDocCount();
System.out.println("typeNm: " + typeNm + ", count: " + docCount);
}
- 집계 API를 사용할 경우 검색 결과는 출력하지 않는다.(setSize = 0)
- addAggregation 메서드를 이용해 정의한 집계 쿼리를 추가한다.
Min Aggregation
String AGGREGATION_NAME = "minMovieId";
String AGG_FIELD_NAME = "movieId";
// Min Aggregation 생성
MinAggregationBuilder aggregation = AggregationBuilders
.min(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- 최솟값을 구하는 집계(문서의 전체 혹은 필터로 질의된 문서 중 가장 작은 값 구함)
Max Aggregation
String AGGREGATION_NAME = "maxMovieId";
String AGG_FIELD_NAME = "movieId";
// Max Aggregation 생성
MaxAggregationBuilder aggregation = AggregationBuilders
.max(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- 최댓값을 구하는 집계(문서의 전체 혹은 필터로 질의된 문서 중 가장 큰 값 구함)
Sum Aggregation
String AGGREGATION_NAME = "sumMovieId";
String AGG_FIELD_NAME = "movieId";
// Sum Aggregation 생성
SumAggregationBuilder aggregation = AggregationBuilders
.sum(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- 전체 문서 혹은 특정 문서의 합계를 구하는 집계
Avg Aggregation
String AGGREGATION_NAME = "avgMovieId";
String AGG_FIELD_NAME = "movieId";
// Avg Aggregation 생성
AvgAggregationBuilder aggregation = AggregationBuilders
.avg(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- 전체 문서 혹은 특정 문서의 평균을 내는 집계
Stats Aggregation
String AGGREGATION_NAME = "statsMovieCd";
String AGG_FIELD_NAME = "movieCd";
// Stats Aggregation 생성
StatsAggregationBuilder aggregation = AggregationBuilders
.stats(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- 기본 집계의 결과와 해당 문서의 개수까지 한 번에 볼 수 있는 집계
Extened Stats Aggregation
String AGGREGATION_NAME = "extendedStatsMovieId";
String AGG_FIELD_NAME = "movieId";
// Extended Stats Aggregation 생성
ExtendedStatsAggregationBuilder aggregation = AggregationBuilders
.extendedStats(AGGREGATION_NAME)
.field(AGG_FIELD_NAME);
- stats Aggregation의 확장 버전으로 stats에서 제공했던 것 외의 제곱의 합, 분산확률, 표준 편차, 표준편차 범위 정보를 추가 제공
Sub Aggregation
String INDEX_NAME = "movie_auto_java";
String TYPE_NAME = "_doc";
// 사용자 기준 Terms Aggregation
String AGGREGATION_NAME_FOR_USER = "repNationNm";
String AGGREGATION_FIELD_FOR_USER = "repNationNm";
// 팔로워 기준 Stats Sub-Aggregation
String AGGREGATION_NAME_FOR_FOLLOWER = "typeNm";
String AGGREGATION_FIELD_FOR_FOLLOWER = "typeNm";
// Stats Sub-Aggregation 생성
StatsAggregationBuilder subAggs = AggregationBuilders
.stats(AGGREGATION_NAME_FOR_FOLLOWER)
.field(AGGREGATION_FIELD_FOR_FOLLOWER);
// Terms Aggregation 생성 + Sub-Aggregation 추가
AggregationBuilder aggs = AggregationBuilders
.terms(AGGREGATION_NAME_FOR_USER)
.field(AGGREGATION_FIELD_FOR_USER)
.size(1000)
.subAggregation(subAggs);
- 다수의 집계 연산을 중첩할 수 있다.
QueryDsl API 사용하기
match All Query
아무 조건 없이 전체 대상으로 질의하고 싶을 때 호출하는 쿼리
String INDEX_NAME = "movie_search";
// Match All 쿼리
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
// 최초 검색 실행 (Scroll 시작)
SearchResponse scrollResp = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30) // 한 번에 가져올 문서 수
.setScroll(new TimeValue(60000)) // Scroll 타임아웃 60초
.get();
- QueryBuilders의 matchAllQuery()에 사용되며, 질의할 문장을 setQuery에 담아 엘라스틱 쿼리로 전송한다.
Full text Queries
루씬에서 제공하는 쿼리문법을 활용해 검색을 질의할 때 사용
1) match Query
String INDEX_NAME = "movie_search";
String FIELD_NAME = "movieNm";
String QUERY = "아이"; // 검색할 키워드
// Match Query 생성
QueryBuilder queryBuilder = QueryBuilders.matchQuery(FIELD_NAME, QUERY);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30) // 한 번에 가져올 문서 수
.get();
- 기본적인 형태소 분석을 통해 검색어를 분석해서 질의를 수행
- 분리된 Term 간에 And, Or 연산을 선택해서 질의 가능
2) Common Terms Query
String INDEX_NAME = "movie_search";
String FIELD_NAME = "movieNm";
String QUERY_KEYWORD = "Family"; // 검색 키워드
// Common Terms Query 생성
QueryBuilder queryBuilder = QueryBuilders.commonTermsQuery(FIELD_NAME, QUERY_KEYWORD);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30) // 한 번에 가져올 문서 수
.get();
- 많이 검색되는 단어와 적게 검색되는 단어 중 어떤 단어가 중요한지를 판단해서 검색 스코어링을 변경하는 알고리즘을 가지는 쿼리
3) Query String Query
String INDEX_NAME = "movie_search";
String FIELD_NAME = "movieNm";
String QUERY_KEYWORD = "버블 OR 하이"; // 검색 키워드
// Query String Query 생성
QueryBuilder queryBuilder = QueryBuilders
.queryStringQuery(QUERY_KEYWORD)
.field(FIELD_NAME);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
// boolean 연산자 포함 예제
QUERY_KEYWORD = "+버블 -하이"; // 포함/제외 조건
queryBuilder = QueryBuilders
.queryStringQuery(QUERY_KEYWORD)
.field(FIELD_NAME);
response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 검색할 때 연산자를 따로 지정하는 것이 아닌 쿼리문 자체에 And, Or 절을 사용해 질의하고 싶을 때 사용한다.
- 특정 키워드를 필수 조건으로 넣거나 빼기 위해 사용
Term level Queries
특정 문자의 일부만 알고 있거나 문자가 아닌 숫자의 범위 혹은 _id 값으로 조회하고 싶을 때 사용하는 API
1) Term Query
String INDEX_NAME = "movie_search";
String FIELD_NAME = "repNationNm";
String QUERY_KEYWORD = "한국"; // 검색 키워드
// Term Query 생성
QueryBuilder queryBuilder = QueryBuilders.termQuery(FIELD_NAME, QUERY_KEYWORD);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30) // 필요 시 한 번에 가져올 문서 수
.get();
- 지정된 필드에 정확한 텀이 들어있는 문서를 찾을 때 사용한다.
- Keyword 타입으로 설정된 필드에서 문서를 찾을 때 사용
2) WildCard Query
String INDEX_NAME = "movie_search";
String FIELD_NAME = "movieNmEn";
String QUERY_KEYWORD = "F?m*"; // 와일드카드 검색 키워드
// Wildcard Query 생성
QueryBuilder queryBuilder = QueryBuilders.wildcardQuery(FIELD_NAME, QUERY_KEYWORD);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30) // 한 번에 가져올 문서 수
.get();
- 특정 단어에 대한 정규 표현식을 이용해 전체 문서를 대상으로 조회하고 싶을 때 사용한다.
Compound Queries
특정 쿼리와 다른 다수의 쿼리를 조합해서 사용하는 API를 의미
1) Bool Query
String INDEX_NAME = "movie_search";
// MUST 조건
String FIELD_NAME_MUST = "repNationNm";
String QUERY_KEYWORD_MUST = "한국";
// MUST_NOT 조건
String FIELD_NAME_MUST_NOT = "repGenreNm";
String QUERY_KEYWORD_MUST_NOT = "드라마";
// SHOULD 조건
String FIELD_NAME_SHOULD = "prdtYear";
String QUERY_KEYWORD_SHOULD = "2017";
// FILTER 조건
String FIELD_NAME_FILTER = "movied";
String QUERY_KEYWORD_FILTER = "20173732";
// Bool Query 생성
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery(FIELD_NAME_MUST, QUERY_KEYWORD_MUST))
.mustNot(QueryBuilders.termQuery(FIELD_NAME_MUST_NOT, QUERY_KEYWORD_MUST_NOT))
.should(QueryBuilders.termQuery(FIELD_NAME_SHOULD, QUERY_KEYWORD_SHOULD))
.filter(QueryBuilders.termQuery(FIELD_NAME_FILTER, QUERY_KEYWORD_FILTER));
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 특정 필드에서 질의문을 넣거나 뺄 때 사용하는 API(여러 개 쿼리 조합 가능)
- must, mustNot, should, filter를 조합해서 쿼리 구성할 수 있다.
2) Dismax Query
String INDEX_NAME = "movie_search";
// DisMax Query에 사용할 필드와 키워드
String FIELD_NAME1 = "repNationNm";
String QUERY_KEYWORD1 = "한국";
String FIELD_NAME2 = "repGenreNm";
String QUERY_KEYWORD2 = "드라마";
// DisMax Query 생성
QueryBuilder queryBuilder = QueryBuilders.disMaxQuery()
.add(QueryBuilders.termQuery(FIELD_NAME1, QUERY_KEYWORD1))
.add(QueryBuilders.termQuery(FIELD_NAME2, QUERY_KEYWORD2))
.boost(1.5f)
.tieBreaker(0.5f);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- tie_breaker를 사용해 스코어를 조정할 수 있는 API
- 가장 많은 점수를 받은 필드를 제외 나머지 필드의 점수를 합산한 후 tie_breaker의 값으로 나눠서 스코어를 재계산
Geo Queries
좌푯값으로 특정 범위 내에 있는 문서를 검색할 때 사용하는 API
1) Geo_Shape Query
String INDEX_NAME = "movie_search_datatype";
String FIELD_NAME = "filmLocation";
// Geo 좌표 생성
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder()
.coordinate(0, 0)
.coordinate(0, 10)
.coordinate(10, 10)
.coordinate(10, 0)
.coordinate(0, 0);
// MultiPoint 도형 생성
MultiPointBuilder multiPoint = new MultiPointBuilder(coordinatesBuilder.build());
// GeoShape Query 생성 (WITHIN 관계)
GeoShapeQueryBuilder queryBuilder = QueryBuilders.geoShapeQuery(FIELD_NAME, multiPoint)
.relation(ShapeRelation.WITHIN);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 지정된 지형과 교차하거나 포함된 지점의 문서를 찾는다.
- API를 사용하기 위해서는 spatial4j와 jts 라이브러리가 필요
2) Geo Bounding Box Query
String INDEX_NAME = "movie_search_datatype";
String FIELD_NAME = "filmLocation";
// Geo Bounding Box Query 생성
QueryBuilder queryBuilder = QueryBuilders.geoBoundingBoxQuery(FIELD_NAME)
.setCorners(40.73, -74.1, 40.717, -73.99); // topLeft(lat, lon), bottomRight(lat, lon)
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 지리적 포인트가 지정한 사각형에 포함되는 문서를 찾을 때 사용하는 API
3) Geo Distance Query
String INDEX_NAME = "movie_search_datatype";
String FIELD_NAME = "filmLocation";
// GeoDistance Query 생성
QueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery(FIELD_NAME)
.point(40, -70) // 기준 좌표 (위도, 경도)
.distance(3, DistanceUnit.KILOMETERS); // 반경 3km
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 특정 문서를 중심으로 일정 거리 내에 있는 지리적 정보가 있는 문서를 찾는 API
4) Geo Polygon Query
String INDEX_NAME = "movie_search_datatype";
String FIELD_NAME = "filmLocation";
// Polygon 좌표 생성
List<GeoPoint> points = new ArrayList<>();
points.add(new GeoPoint(40, -70));
points.add(new GeoPoint(30, -80));
points.add(new GeoPoint(20, -90));
// GeoPolygon Query 생성
QueryBuilder queryBuilder = QueryBuilders.geoPolygonQuery(FIELD_NAME, points);
// 검색 실행
SearchResponse response = client.prepareSearch(INDEX_NAME)
.setQuery(queryBuilder)
.setSize(30)
.get();
- 지정한 다각형 내의 지리적 포인트가 있는 문서를 찾는 API
'Elastic Search' 카테고리의 다른 글
| Ch09. 엘라스틱서치와 루씬 이야기 - 샤드 VS 루씬 인덱스 (0) | 2025.10.07 |
|---|---|
| Ch09. 엘라스틱서치와 루씬 이야기 - 클러스터 관점에서 구성요소 살펴보기 (0) | 2025.10.05 |
| Ch08. 엘라스틱서치 클라이언트 - 엘라스틱서치 클라이언트의 이해 (0) | 2025.10.02 |
| Ch07. 한글 검색 확장 기능 - 자바카페 플러그인 (0) | 2025.09.28 |
| Ch07. 한글 검색 확장 기능 - 한글 키워드 자동완성 (0) | 2025.09.28 |