엘라스틱 서치 With 스프링

김파란·2024년 8월 29일

Spring-Library

목록 보기
6/7

1. 환경설정

@Configuration
public class Config  extends ElasticsearchConfiguration{

    @Override
    public ClientConfiguration clientConfiguration() {
        return ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();
    }
}

2. 리파지토리

  • 레디스처럼 2가지가 가능하다
  1. 스프링에서 제공하는 리파지토리
  2. ElasticsearchOperations elasticsearchOperations

1). 스프링에서 제공하는 리파지토리

  • CRUDRepository처럼 사용하면 된다
//결과 값은 SearchHits<T> 객체를 활용하여 총 결과 개수를 받아올 수 있음
//옵션으로는 List<T>, Stream<T>, List<SearchHit<T>>, Stream<SearchHit<T>>, SearchPage<T> 등 사용 가능
public interface TestRepository extends ElasticsearchRepository<Test, String> {

    SearchHits<Test> findByTitle(String title);
    SearchHits<Test> findByContent(String content);

}

2). ElasticsearchOperations

참고) https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-bool-prefix-query.html
https://esbook.kimjmin.net/05-search/5.1-query-dsl
https://velog.io/@haden/spring-Spring-%EC%97%90%EC%84%9C-Elastic-Search-%ED%99%9C%EC%9A%A9-1
https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/template.html

  • 사용법의 거의 동일하다
  • save로 저장하고 Person person = elasticsearchOperations.get(id.toString(), Person.class);으로 가져오기
  • 다만 복잡한 쿼리를 작성할 수 있도록 해준다
// 간단한 쿼리
Criteria criteria = new Criteria("price").is(42.0);
Query query = new CriteriaQuery(criteria);

// 조금 복잡해진 쿼리
Criteria miller = new Criteria("lastName").is("Miller")  
  .subCriteria(                                          
    new Criteria().or("firstName").is("John")            
      .or("firstName").is("Jack")                        
  );
Query query = new CriteriaQuery(criteria);

// 스트링 쿼리
Query query = new StringQuery("{ \"match\": { \"firstname\": { \"query\": \"Jack\" } } } ");
SearchHits<Person> searchHits = operations.search(query, Person.class);

// 네이티브 쿼리
Query query = NativeQuery.builder()
	.withAggregation("lastNames", Aggregation.of(a -> a
		.terms(ta -> ta.field("lastName").size(10))))
	.withQuery(q -> q
		.match(m -> m
			.field("firstName")
			.query(firstName)
		)
	)
	.withPageable(pageable)
	.build();

SearchHits<Person> searchHits = operations.search(query, Person.class);

3. 엔티티

@Document(indexName = "alcohols") // 인덱스 이름 설정, 인덱스를 자동생성하는 옵션인 createIndex는 디폴트값이 true이므로 명시하지 않아도 된다
@Getter
@Setter
@Setting(replicas = 0) // 레플리카 개수조절, 운영시에는 노드 개수를 늘리고 레플리카 개수를 늘려 안정적으로 해야한다
public class AlcoholDocument {
    // Id 어노테이션을 특정 속성을 달아주거나, 속성명이 Id인 필드값을 생셩하면 es의 _id와 자동연결
    // _id와 연결되면 타입과 인덱싱이 강제
    // 따라서 DB의 id값을 담는 필드인 alcoholId는 따로 빼줌
    @Id
    private String id;

    // 각 필드의 타입을 매핑하고, 분석기(analyzer) 설정가능
    // 복합적인 설정이 필요한 경우 FieldType.Object를 달아주고 inner class를 새로 생성해서 클래스 내부에서 타입매핑
    // 인덱싱을 원하지 않는 필드는 index=false 적용
    @Field(type = FieldType.Long, index = false, docValues = false)
    private Long alcoholId;

    // 똑같은 String이지만 단어가 존재하는 return 해준다
    @Field(type = FieldType.Text, analyzer = "nori")
    private String title;

    // 키워드는 완전히 똑같이 검색해야 검색이 된다
    @Field(type = FieldType.Keyword, index = false, docValues = false)
    private String category;

    @Field(type = FieldType.Object)
    private List<TagDocument> tags = new ArrayList<>();

    // @WriteOnlyProperty
    // searchKeys 리스트는 추후 검색 조건으로 사용되지만, 검색결과에는 띄우지 않는 속성
    // 어노테이션을 달아 인덱싱할 때는 넣어주고, 추후 검색 결과를 불러올 때는 값을 가져오지 않음
    @Field(type = FieldType.Object)
    @WriteOnlyProperty
    private List<AlcSearchKeyDocument> searchKeys = new ArrayList<>();

    // LocalDateTime 타입 지정, 이름도 지정할 수 있다
    @Field(name = "producer_created_at", type = FieldType.Date, format = DateFormat.basic_date_time)
    private LocalDateTime producerCreatedAt;

참고)
https://j-1001000.tistory.com/1
https://velog.io/@yeomyaloo/%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1-%EC%84%9C%EC%B9%98elasticsearch%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%97%B0%EB%8F%99%ED%95%B4%EB%B3%B4%EC%9E%90
https://ksb-dev.tistory.com/324

0개의 댓글