es에 데이터도 저장하고~ 간단한 검색도 하고~
spring에서 사용해야 하는데...
어찌 좀 편하게 방법이 없을까... 고민하던중...
spring.io 에 보면 어지간한 저장소와 연결할 수 있는 spring-data 프로젝트가 있더군요!
음...그래서 이것저것 막 삽질해보는데...뭐가 버전이 안맞고 안되고..어휴 ㅠㅠ
maven에서 jar 참조하는 버전을 변경하고 해보는데도..안되고... 어휴 ㅠㅠ
es에 비해 버전업이 너무 느려 ㅠㅠ
es 버전을 7.1.1을 사용하는데...
결국 대강 JPA 흉내라도 내보자는 심산으로...만들어 봐야겠다~~
결심
일단 PO인 도메인(이하 Docu)부터 생성...
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@lombok.ToString
@Document(indexName="zipcode")
public class DocuZipcode implements Serializable{
/**
*
*/
private static final long serialVersionUID = -3670872846932659171L;
@Id
public String buildingControlNumber;
public String lawTownCode;
public String city;
public String ward;
public String town;
public String lee;
public String isMountaion;
public String jibun;
public String jibunSub;
public String roadCode;
public String road;
public String isUnderground;
public String buildingNumber;
public String subBuildingNumber;
public String buildingName;
public String buildingNameDetail;
public String dongNumber;
public String dongCode;
public String dongName;
public String zipcode;
public String zipcodeNumber;
public String massDlvr;
public String moveReasonCode;
public String stdnDate;
public String preRoadName;
public String cityBuildingName;
public String isPublic;
public String newZipCode;
public String idDetailAddr;
public String etc1;
public String etc2;
public String message;
public String path;
public String host;
}
public으로 만든 이유는 나중에 접근하기 위해서...
private으로 해도 접근 하는 방식이 있는 걸로 아는데...찾아보기도 귀찬고..ㅠ
@Document 라는 어노테이션은
대강 만들었어요!
클래스 이름을 인덱스 이름으로 사용 할 수는 없기에...
내용을 보자면..
@Target(TYPE)
@Retention(RUNTIME)
public @interface Document {
String indexName() default "";
String typeName() default "_doc";
}
ES 6부터는 어차피 인덱스 하나당 타입이 하나고, 해당 타입명은 기본으로 _doc을 사용하기에...
그리고 입력 삭제 검색 등 기본적인 기능을 다 때려박은 클래스 하나 생성..
public abstract class AbstractRepo <PK extends Serializable, T>{
@Autowired
private Client client;
private final Class<T> persistentClass;
protected Client getClient() {
return client;
}
public AbstractRepo(){
this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
public UpdateByQueryRequestBuilder updateByQuery() {
String index = getIndexName(persistentClass);
UpdateByQueryRequestBuilder updateByQuery =
new UpdateByQueryRequestBuilder(client, UpdateByQueryAction.INSTANCE);
updateByQuery.source(index);
return updateByQuery;
}
public SearchRequestBuilder searchRequestBuilder() {
String index = getIndexName(persistentClass);
SearchRequestBuilder reqBuilder = client.prepareSearch(index)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
return reqBuilder;
}
public List<T> fullTextSearch(String text) {
List<T> ts = new ArrayList<>();
String index = getIndexName(persistentClass);
SearchResponse response = client.prepareSearch(index)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.matchQuery("fullTextSearch", text)).get();
SearchHit[] hits = response.getHits().getHits();
for(SearchHit hit : hits) {
String jsonString = hit.getSourceAsString();
ObjectMapper mapper = new ObjectMapper();
try {
T t = mapper.readValue(jsonString, persistentClass);
ts.add(t);
} catch (IOException e) {
e.printStackTrace();
}
}
return ts;
}
public IndexRequestBuilder builder(T t, String routing) {
String index = getIndexName(persistentClass);
String type = getTypeName(persistentClass);
String id = getId(t);
if(id == null) {
throw new ServiceException("E", "id is null");
}
IndexRequestBuilder indexRequestBuilder = null;
try {
ObjectMapper mapper = new ObjectMapper();
String jsonString;
jsonString = mapper.writeValueAsString(t);
indexRequestBuilder = client.prepareIndex(index, type, id)
.setSource(jsonString, XContentType.JSON);
if(!StringUtil.isBlank(routing)) {
indexRequestBuilder.setRouting(routing);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return indexRequestBuilder;
}
public IndexResponse index(T t, String routing) {
IndexResponse response = null;
try {
IndexRequestBuilder indexRequestBuilder = this.builder(t, routing);
response = indexRequestBuilder.get();
} catch (Exception e) {
throw new ServiceException("E", "인덱스 생성에 실패하였습니다");
}
return response;
}
public BulkRequestBuilder bulkRequest() {
BulkRequestBuilder bulkRequest = client.prepareBulk();
return bulkRequest;
}
public BulkResponse bulk(List<T> ts) {
BulkRequestBuilder bulkRequest = client.prepareBulk();
for(T t : ts) {
bulkRequest.add(this.builder(t, null));
}
BulkResponse bulkResponse = bulkRequest.get();
if (bulkResponse.hasFailures()) {
throw new ServiceException("E", "bulk failure");
}
return bulkResponse;
}
public void update(T t) {
String index = getIndexName(persistentClass);
String type = getTypeName(persistentClass);
String id = getId(t);
if(id == null) {
throw new ServiceException("E", "id is null");
}
try {
ObjectMapper mapper = new ObjectMapper();
String jsonString;
jsonString = mapper.writeValueAsString(t);
UpdateResponse updateResponse = client.prepareUpdate(index, type, id)
.setDoc(jsonString, XContentType.JSON).get();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
public T get(PK id, String routing) {
String index = getIndexName(persistentClass);
String type = getTypeName(persistentClass);
GetRequestBuilder request = client.prepareGet(index, type, id.toString());
if(!StringUtil.isBlank(routing)) {
request.setRouting(routing);
}
GetResponse response = request.get();
String jsonString = response.getSourceAsString();
if(jsonString == null) {
return (T)null;
}
ObjectMapper mapper = new ObjectMapper();
try {
T t = mapper.readValue(jsonString, persistentClass);
return t;
} catch (IOException e) {
return (T)null;
}
}
protected String getId(T t) {
Field[] fields = t.getClass().getDeclaredFields();
for(Field f : fields) {
if(f.isAnnotationPresent(Id.class)) {
Object obj;
try {
obj = f.get(t);
return obj==null?null:obj.toString();
} catch (IllegalArgumentException | IllegalAccessException e) {
// field를 접근성을 위해 public으로 선언 했으며, 없는게 나올수가 없으므로 위 exception은 발생이 불가능 한거 아닌가...
e.printStackTrace();
}
}
}
return null;
}
protected String getIndexName(Class<T> clazz) {
Document document = clazz.getAnnotation(Document.class);
return document.indexName();
}
protected String getTypeName(Class<T> clazz) {
Document document = clazz.getAnnotation(Document.class);
return document.typeName();
}
}
각각의 Exception처리는 뭐 편하신대로 하시면 더 좋을 거 같아요. 너무 대충해서..
참고로 @Id라는 어노테이션은 javax.persistence.Id 입니다.
해당 어노테이션이 있는 필드의 값을 도큐먼트의 _id로 사용하고자 이렇게 하였어요!
물론 그걸 알기 위해 위에 클래스에서 reflect.Field를 통한 접근도 하고있죠.
이래서 Docu에서 필드의 접근자를 public을 사용했고요.
그럼 이제 각 Docu별로 ES에 접근하기 위한 레파지토리를 만들어 보도록 할게요!
@Repository("docuZipcodeRepository")
public class DocuZipcodeRepository extends AbstractRepo<String, DocuZipcode>{
}
내용은~
별게 없어요.
이제 이 안의 내용은 사용에 따라 채우시면 될거 같아요.
this.searchRequestBuilder(); 를 사용해서 검색빌더를 생성하고 검색을 하고..
Hits 결과를 문자열로 받아서 오브젝트 매퍼를 이용하여 원하는 클래스로 변환하고...
여기서 더 공과 시간을 들이면 편해질지 모르겠으나, 일단 이정도에서 만족하며...
저는 그럼 일을 하도록 하겠습니다~ ㅋㅋㅋ
일을 위한 일을 하느라 시간을 쓸데 없이 많이 쓴듯...
'서버 > ES' 카테고리의 다른 글
[Elastic] 주소데이터 logstash로 ES에 넣기! (1) | 2020.06.18 |
---|---|
[ElasticSearch] 플러그인 만들기 (version 7) (2) | 2019.08.02 |
[ElasticSearch] X-PACK 보안(인증) 기능 포함 무료~!!(BASIC) (0) | 2019.06.03 |
[ElasticSearch] Nori - Index 생성 (0) | 2019.04.26 |
[ELK] Tomcat Log 적재 ... 그리고 curator (0) | 2019.04.25 |