티스토리 뷰

이번 포스팅은 Document API에 대한 내용이다.

공식 가이드는 아래의 사이트에서 확인할 수 있다.

www.elastic.co/guide/en/elasticsearch/client/java-rest/6.8/java-rest-high-supported-apis.html

 

Document APIs | Java REST Client [6.8] | Elastic

 

www.elastic.co

 

Document API들은 문서 생성(색인 생성), 문서 조회, 문서 업데이트, 문서 삭제, 그리고 대량의 문서 생성을 위한 API들을 제공한다.

※ 이전 포스팅에서도 밝힌 바와 같이 High level REST client를 개인적으로 사용하기 편리하도록 작성한 것입니다.

API호출시 변경되는 부분만을 별도로 생성한 클래스의 메소드 argument로 받아 향후 이 메소드만 호출하여 쓰기 위한 용도이니 상세한 내용은 elasticsearch 공식 가이드를 참조하길 바랍니다.


1. 문서 생성

 

문서를 생성하기 위해서는 인덱스명, 타입명, 문서ID, 문서 내용이 필요하다.

REST client api에서는 문서 내용을 입력하기 위해 여러가지의 타입을 제공하는데

XContentBuilder 타입, String 타입, Map 타입을 필요에 따라 골라서 사용하면 된다.

	public IndexResponse createDocument(String indexName, String typeName, String _id, XContentBuilder indexBuilder) {
		
		// 데이터 추가
		IndexRequest request = new IndexRequest(indexName, typeName, _id);
		request.source(indexBuilder);
		
		return _createDocument(request, indexName, _id);
	}
	
	/**
	 * 문서를 해당 인덱스에 생성한다.
	 * 문서는 String 로 기술
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param jsonString
	 * @return
	 */
	public IndexResponse createDocument(String indexName, String typeName, String _id, String jsonString) {
		
		// 데이터 추가
		IndexRequest request = new IndexRequest(indexName, typeName, _id);
		request.source(jsonString, XContentType.JSON);
		
		return _createDocument(request, indexName, _id);
	}
	
	/**
	 * 문서를 해당 인덱스에 생성한다.
	 * 문서는 Map<String, Object> 로 기술
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param jsonMap
	 * @return
	 */
	public IndexResponse createDocument(String indexName, String typeName, String _id, Map<String, Object> jsonMap) {
		
		// 데이터 추가
		IndexRequest request = new IndexRequest(indexName, typeName, _id);
		request.source(jsonMap);
		
		return _createDocument(request, indexName, _id);
	}
	
	/**
	 * 문서를 해당 인덱스에 생성
	 * @param request
	 * @param indexName
	 * @param _id
	 * @return
	 */
	private IndexResponse _createDocument(IndexRequest request, String indexName, String _id) {
		// 결과 조회
		IndexResponse response = null;
		try {
			response = client.index(request, RequestOptions.DEFAULT);
			log.info(response.status() + " in " +indexName + " :: created id=" + _id);
		} catch (ElasticsearchException | IOException e) {
			if(((ElasticsearchException) e).status().equals(RestStatus.CONFLICT)) {
				log.error("문서 생성 실패");
			}
			log.error(e);
		}
		
		return response;
	}

 

문서 생성은 IndexRequest 클래스가 담당하며 이 클래스의 생성자는 인덱스명, 타입명, 문서ID를 받을 수 있다.

source() 메소드에서 문서 내용을 입력하기 위한 타입 중 하나를 입력할 수 있다.

 

테스트 - XContentBuilder

	@Test
	public void createDocument1() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		
		XContentBuilder indexBuilder = XContentFactory.jsonBuilder()
			.startObject()
				.field("code", "2021")
				.field("title", "나니아 연대기")
				.field("date", new Date())
			.endObject();
		docApi.createDocument("test", "_doc", "1", indexBuilder);
		
		indexBuilder = XContentFactory.jsonBuilder()
			.startObject()
				.field("code", "2022")
				.field("title", "Walk to Remember")
				.field("date", new Date())
			.endObject();
		docApi.createDocument("test", "_doc", "2", indexBuilder);
		
		api.close();
	}

 

테스트 - String

	@Test
	public void createDocument2() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.KOREAN);
		String jsonString = "{" +
		        "\"code\":\"2025\"," +
		        "\"title\":\"퍼스트 어벤져\"," +
		        "\"date\":\"" + format.format(new Date()) +"\"" +
		        "}";
		IndexResponse result = docApi.createDocument("test", "_doc", "5", jsonString);
		api.close();

		System.out.println(result.getResult().toString());
	}

 

테스트 - Map

	@Test
	public void createDocument3() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		
		Map<String, Object> jsonMap = new HashMap<>();
		jsonMap.put("code", "2026");
		jsonMap.put("title", "나의 캡틴 그대");
		jsonMap.put("date", new Date());
		
		IndexResponse result = docApi.createDocument("test", "_doc", "9", jsonMap);
		api.close();
		
		System.out.println(result.getResult().toString());
	}

 

 

2. 문서 조회

문서 조회는 GetRequest 클래스가 담당한다. 

문서 생성과 마찬가지로 생성자에 인덱스명, 타입명, 문서ID를 입력할 수 있다.

	/**
	 * 문서를 조회하고 해당 문서의 source를 반환
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @return
	 */
	public GetResponse getDocument(String indexName, String typeName, String _id) {
		GetRequest request = new GetRequest(indexName, typeName, _id);
		return _getDocument(request);
	}
	
	/**
	 * 문서를 조회하고 해당 문서의 특정 필드만을 반환
	 * 이 필드는 매핑에서 저장하도록 설정이 되어 있어야만 가능하다.
	 * @param indexName
	 * @param typeName
	 * @param fieldName
	 * @param _id
	 * @return
	 */
	public GetResponse getDocument(String indexName, String typeName, String[] fieldName, String _id) {
		GetRequest request = new GetRequest(indexName, typeName, _id);
		//fieldName만을 결과로 반환
		request.storedFields(fieldName); 
		return _getDocument(request);
	}

	/**
	 * 문서를 조회하고 해당 문서의 source를 반환
	 * source에 포함할 필드와 포함하지 않을 필드는 인수로 넘겨 받은 값에 따라 정해진다.
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param includeField
	 * @param excludeField
	 * @return
	 */
	public GetResponse getDocument(String indexName, String typeName, String _id, String[] includeField, String[] excludeField) {
		GetRequest request = new GetRequest(indexName, typeName, _id);
		//결과로 반환하는 source에 포함할 필드와 포함하지 않을 필드를 설정
		FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includeField, excludeField);
		request.fetchSourceContext(fetchSourceContext); 
		return _getDocument(request);
	}
	
	/**
	 * 문서를 조회한다.
	 * @param request
	 * @return
	 */
	private GetResponse _getDocument(GetRequest request) {
		GetResponse response = null;
		try {
			response = client.get(request, RequestOptions.DEFAULT);
			if(!response.isExists()) {
				log.info("문서를 찾을 수 없습니다.");
				return null;
			}
		} catch (ElasticsearchException  e) {
			if (e.status() == RestStatus.NOT_FOUND) {
				log.error("인덱스를 찾을 수 없습니다.");
			}
		} catch (IOException e) {
			log.error(e);
		}
		return response;
	}

문서조회시 반환되는 source 필드값에 특정 필드를 포함할지 포함하지 않을지를 설정할 수도 있다.

 

테스트

	@Test
	public void getDocument3() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		
		String[] includeField= {"code", "title"};
		String[] excludeField= {"date"};
		GetResponse result = docApi.getDocument("test", "_doc", "6", includeField, excludeField);
		api.close();
		
		if(result != null) {
			System.out.println(result.getIndex() + "\t" + result.getType() + "\t" + result.getId());
			System.out.println(result.getSourceAsString());
		}
	}

 

3. 복수개의 문서 조회

한번의 통신으로 여러개의 문서를 조회할 수 있는 기능은 MultiGetRequest 클래스가 담당한다.

위의 문서조회와 마찬가지로 특정 필드를 포함할지 말지를 설정하여 조회를 할 수 도 있고, 문서ID로만으로 조회를 할 수도 있다.

	/**
	 * 복수개의 문서를 조회하고 해당 문서의 source를 반환
	 * source에 포함할 필드와 포함하지 않을 필드는 인수로 넘겨 받은 값에 따라 정해진다.
	 * @param indexName
	 * @param typeName
	 * @param includeField
	 * @param excludeField
	 * @param _id
	 * @return
	 */
	public MultiGetResponse getMultiDocument(String indexName, String typeName, String[] includeField, String[] excludeField, String... _id) {
		MultiGetRequest request = new MultiGetRequest();
		FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includeField, excludeField);
		for(String id : _id) {
			request.add(new MultiGetRequest.Item(indexName, typeName, id).fetchSourceContext(fetchSourceContext));
		}
		MultiGetResponse response = null;
		try {
			response = client.mget(request, RequestOptions.DEFAULT);
			
		} catch (IOException e) {
			log.error(e);
		}
		return response;
	}

 

테스트

	@Test
	public void getMultiDocument3() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		String[] includeField= {"code", "title"};
		String[] excludeField= {"date"};
		MultiGetResponse result = docApi.getMultiDocument("test", "_doc", includeField, excludeField, "6", "7", "1");
		api.close();
		
		if(result != null) {
			Iterator<MultiGetItemResponse> iter = result.iterator();
			MultiGetItemResponse itemResponse;
			while(iter.hasNext()){
				itemResponse = iter.next();
				GetResponse response = itemResponse.getResponse();  
				if(response.isExists()) {
					System.out.println(response.getSourceAsString());
				}else {
					System.out.println(response);
				}
			}
			
		}
	}

문서ID가 1,6,7번인 문서를 조회하여 code, title 필드값을 결과로 가져오고 date 필드값은 결과에 포함시키지 않는다.

 

4. 문서 존재 여부

문서 존재 여부는 조회에 사용하는 클래스와 같이 GetRequest를 사용한다.

	/**
	 * 문서가 해당 인덱스에 존재하는지 여부를 반환한다.
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @return
	 */
	public Boolean existDocument(String indexName, String typeName, String _id) {
		GetRequest request = new GetRequest(indexName, typeName, _id);
		
		request.fetchSourceContext(new FetchSourceContext(false));
		request.storedFields("_none_");
		boolean exists = false; 
		try {
			exists = client.exists(request, RequestOptions.DEFAULT);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return exists;
		
	}

테스트

	@Test
	public void getDocument4() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		
		boolean result = docApi.existDocument("test", "_doc", "7");
		api.close();
		
		System.out.println(result);
	}

 

5. 문서 업데이트

업데이트는 문서 생성과 같이 여러가지 타입의 문서내용을 입력할 수 있다.

여기서는 위의 문서 생성에서와 같이 XContentBuilder, String, Map을 사용하도록 구현하였다.

	/**
	 * 문서를 업데이트 한다.
	 * 업데이트 내용을 json형태의 string으로 기술한다.
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param jsonString
	 * @return
	 */
	public UpdateResponse updateDocument(String indexName, String typeName, String _id, String jsonString) {
		UpdateRequest request = new UpdateRequest(indexName, typeName, _id);
		request.doc(jsonString, XContentType.JSON);
		
		return _updateDocument(request, indexName, _id);
	}

	/**
	 * 문서를 업데이트 한다.
	 * 업데이트 내용을 Map<String, Object>으로 기술한다.
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param jsonMap
	 * @return
	 */
	public UpdateResponse updateDocument(String indexName, String typeName, String _id, Map<String, Object> jsonMap) {
		UpdateRequest request = new UpdateRequest(indexName, typeName, _id);
		request.doc(jsonMap, XContentType.JSON);
		
		return _updateDocument(request, indexName, _id);
	}

	/**
	 * 문서를 업데이트 한다.
	 * 업데이트 내용을 XContentBuilder으로 기술한다.
	 * @param indexName
	 * @param typeName
	 * @param _id
	 * @param builder
	 * @return
	 */
	public UpdateResponse updateDocument(String indexName, String typeName, String _id, XContentBuilder builder) {
		UpdateRequest request = new UpdateRequest(indexName, typeName, _id);
		request.doc(builder, XContentType.JSON);
		
		return _updateDocument(request, indexName, _id);
	}
	
	/**
	 * 문서의 내용을 업데이트 한다.
	 * @param request
	 * @param indexName
	 * @param _id
	 * @return
	 */
	private UpdateResponse _updateDocument(UpdateRequest request, String indexName, String _id) {
		UpdateResponse response = null;
		try {
			response = client.update(request, RequestOptions.DEFAULT);
			log.info(response.status() + " in " +indexName + " :: updated id=" + _id);
		} catch (ElasticsearchException | IOException e) {
			if(((ElasticsearchException) e).status().equals(RestStatus.CONFLICT)) {
				log.error("문서 업데이트 실패");
			}
			log.error(e);
		}
		
		return response;
	}

테스트

	@Test
	public void updateDocument2() throws IOException {
		ClientApi api = new ClientApi(ip);
		DocumentApi docApi = api.getDocumentApi();
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("code", "111");
		jsonMap.put("title", "타이틀");
		jsonMap.put("date", new Date());
		UpdateResponse result = docApi.updateDocument("test", "_doc", "1", jsonMap);
		api.close();
		
		if(result != null) {
			System.out.println(result.getResult().toString());
			
		}
	}

위에서 사용한 전체 코드는

https://github.com/joyhong85/elasticsearch-client

에서 확인할 수 있다.

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함