ELK 도입기(3) - Elasticsearch Spring 연동

Jongmyung Choi·2023년 11월 5일
post-thumbnail

보안설정
설치
ELK에 대한 설치와 보안설정은 이전 글을 참고해주세요 😁

개요

ELK 에 대한 설치와 보안설정이 끝났으니 이제 본격적으로 Spring과 연동하여 사용해볼 것이다.
Spring 에서 Elasticsearch 를 사용하기 위해 필요한 클래스들과 데이터를 저장하기에 앞서 필요한 설정법에 대해 알아보자.

Spring 설정

설정 클래스가 Redis 설정할 때랑 굉장히 비슷하고 간단하다.

ElasticsearchConfig

@EnableElasticsearchRepositories(basePackageClasses = ElasticStoreRepository.class)
@EnableFeignClients
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {

	@Value(value = "${elasticsearch.host}")
	private String ELASTIC_URL;
	@Value(value = "${elasticsearch.port}")
	private String ELASTIC_PORT;
	@Value(value = "${elasticsearch.user_name}")
	private String ELASTIC_USER_NAME;
	@Value(value = "${elasticsearch.user_password}")
	private String ELASTIC_USER_PASSWORD;
	@Override
	@Bean
	public RestHighLevelClient elasticsearchClient() {
		ClientConfiguration clientConfiguration = ClientConfiguration.builder()
			.connectedTo(ELASTIC_URL+":"+ELASTIC_PORT)
			.withBasicAuth(ELASTIC_USER_NAME,ELASTIC_USER_PASSWORD)
			.build();
		return RestClients.create(clientConfiguration).rest();

	}
	@Bean
	public ElasticsearchOperations elasticsearchOperations(){
		return new ElasticsearchRestTemplate(elasticsearchClient());
	}

}

application.yml

elasticsearch:
  host: 도메인 주소
  port: 9200
  user_name : 보안 설정에서 입력한 ID
  user_password : 보안 설정에서 입력한 PASSWORD

Host와 Port 이전 글에서 보안설정을 할 때 입력했던 ID와 PASSWORD를 환경변수로 빼주었다.

ElasticStoreRepository

public interface ElasticStoreRepository extends ElasticsearchRepository<Store,Long> {
}

ElasticsearchRepository 를 상속한 클래스를 생성한다.

Store

@Document(indexName = "stores")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class Store {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	private String name;

	private String address;

	@Embedded
	private Location location;

	public static Store from(StoreDto storeDto) {
		return Store.builder()
			.name(storeDto.getName())
			.location(storeDto.getLocation())
			.address(storeDto.getAddress())
			.build();
	}
}

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Embeddable
public class Location {
	@Column(nullable = false)
	double lat;
	@Column(nullable = false)
	double lon;
}

설정도 간단하고 전체적으로 JPA 사용하듯 사용하면 된다!
데이터를 저장하는 방법은 다음글에서 설명한다.

하지만 그 전에 Elasticsearch 에서 해줘야 될 인덱스 관련 설정이 있다.

Elasticsearch 인덱스 구조 설정

인덱스의 구조를 미리 설정하고 analyzer를 지정해주어야 데이터를 검색할 때 편리하게 검색할 수 있다.

PUT stores
	{
    "settings": {
    "analysis": {
      "tokenizer": {
        "korean_nori_tokenizer": {
          "type": "nori_tokenizer",
          "decompound_mode": "mixed"
        }
      },
      "analyzer": {
        "nori_analyzer": {
          "type": "custom",
          "tokenizer": "korean_nori_tokenizer",
          "filter": ["nori_posfilter"]
        }
      },
      "filter": {
        "nori_posfilter": {
          "type": "nori_part_of_speech",
          "stoptags": [
            "E", "IC", "J", "MAG", "MM", "NA", "NR", "SC", "SE", "SF", "SH", "SL", "SN", "SP", "SSC", "SSO", "SY", "UNA", "UNKNOWN", "VA", "VCN", "VCP", "VSV", "VV", "VX", "XPN", "XR", "XSA", "XSN", "XSV"
          ]
        }
      }
    }
  },
    "mappings": {
        "properties": {
            "id": {
                "type": "long"
            },
            "name": {
                "type": "text",
                "analyzer": "nori_analyzer"
            },
            "address": {
                "type": "keyword"
            },
             "location": {
                "type": "geo_point"
            },
        }
    }
}

다음과 같이 Stores 인덱스를 생성해주고 nori_tokenizer를 지정하고
필드값들의 타입을 명시해주자.

Type

text 타입의 경우 입력된 문자열을 analyzer를 통해 쪼개서 역색인 구조로 만든다.
따라서 name의 경우는 text 타입으로 지정하였다.
이로 인해서 예를들어 찜닭이라는 이름을 찜 혹은 닭 으로만 검색해도 찾을 수 있도록 하였다.

keyword 타입은 문자열 자체로 색인되어 저장한다.
address의 경우 따로 검색조건에 있지 않기에 그렇게 저장하였다.

geo_point 타입은 위도와 경도를 쌍으로 가지고 이를 이용해 제공하는 다양한 위치 기반 쿼리를 사용하여 검색을 할 수 있다.

			"lat": {
                "type": "double"
            },
            "lon": {
                "type": "double"
            }

이렇게 따로 저장하면 안된다. 무조건 geo_point 타입으로 저장해야 다양한 쿼리를 사용할 수 있다.

profile
총명한 개발자

0개의 댓글