개발일기
ElasticSearch을 사용한 학교 정보 검색어 자동완성 본문
앞에서는 ElasticSearch를 사용하기 위한 docker-compose로 다운로드 받는 방법을 소개하였다.
https://seounggyun.tistory.com/259
docker-compose ELK 설치
우선 ELK를 사용하는 이유는 ElasticSearch를 사용하여 자동완성 기능을 만들 예정이며, Logstash , kibana, elasticSearch를 통하여 logback을 통하여 log를 분석하여 그래프로 볼 예정이다.이에 따라서 해당 기
seounggyun.tistory.com
이제는 시간이 좀 많이 지났지만 ElasticSearch를 사용해보자.
우선 ElasticSearch가 최근에 많이 바뀌어 구글에 있는 내용들은 잘 동작하지 않는 코드가 많다. 덕분에 ElasticSearch Docs와 Gpt와의 만담을 통해서 구현을 완료하였다.
본격적으로 세팅하는 방법에 대해 알아보자
🔥 ElasticSearchConfig
package darkoverload.itzip.global.config.elastic;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
@Configuration
@EnableElasticsearchRepositories(basePackages = "org.springframework.data.elasticsearch.repository")
public class ElasticSearchConfig extends ElasticsearchConfiguration {
@Value("${spring.elasticsearch.uris}")
private String elasticsearchUrl;
@Value("${spring.elasticsearch.username}")
private String username;
@Value("${spring.elasticsearch.password}")
private String password;
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(elasticsearchUrl)
.withBasicAuth(username, password)
.build();
}
}
해당 설정은 ElasticSearch에 해당하는 Config이다.
여기서 핵심은 JPARepository를 Import받으면 Spring Boot는 기본적으로 JPA 레포지토리를 기준으로 레포를 찾아오기에 여기서 @EnableElasticSearchRepositories를 통해서 베이스 패키지를 등록하여 사용해주어야 한다.
취준생 프로젝트에서는 다양한 DB를 사용하고 있으며 이에 따라서 DB를 SpringBoot가 Repository를 읽을 수 있게 처리를 하였는데 이에 대한 부분은 팀원이 작성한 글이 있어 해당 글을 참고하면 좋을 듯하다.
https://naturecancoding.tistory.com/120
[Database/Error] spring에서 db 2개 사용할 때 생기는 Bean 문제 해결
1. 해결 방법jpa가 repository를 탐색하지 않도록 하는 커스텀 어노테이션을 사용해서 Jpa의 @ComponentScan.Filter에 걸리도록해 리jpa리파지토리 등록을 자동으로 하지 않도록 했다.QuerydslConfig@EnableJpaReposi
naturecancoding.tistory.com
이 글은 진짜 맛있긴하더라 석원님 고마워요🙏
나의 레포지토리 구조이다.
repository/
├── custom/
│ ├── CustomSchoolRepository.java
│ └── CustomSchoolRepositoryImpl.java
└── SchoolRepository.java
이런식으로 CustomSchoolRepository를 작성한 이유는 JPA, ElasticSearch를 추후에 있을 곳에 동시에 적용하기 위해 위에 패키지 구조를 택하였다. 하지만 다 끝나고 보니 괜히 이렇게 했나 엘라스틱 서치만 써서 학교정보만 단순히 조회해올텐데라는 생각이 들었다.
아직 갈 길이 멀다.
@RequiredArgsConstructor
public class CustomSchoolRepositoryImpl implements CustomSchoolRepository{
private final ElasticsearchOperations elasticsearchOperations;
@Override
public List<String> searchSchool(String schoolName) {
final int size = 10;
Criteria criteria = new Criteria("school_name").contains(schoolName);
PageRequest pageRequest = PageRequest.of(0, size);
CriteriaQuery query = new CriteriaQuery(criteria, pageRequest);
// 검색 수행
return elasticsearchOperations.search(query, SchoolDocument.class)
.stream()
.map(hit->hit.getContent().getSchoolName())
.collect(Collectors.toList());
}
}
😇 ElasticsearchOperations
ElasticsearchOperations는 Elasticsearch와의 통신을 추상화하는 스프링 데이터의 인터페이스입니다. 이 인터페이스를 사용하여 Elasticsearch에서 데이터를 검색하고 조작할 수 있습니다.
🤔 Criteria
Criteria는 Elasticsearch에서 검색할 조건을 정의하는 클래스입니다. 여기서는 school_name 필드가 주어진 schoolName 문자열을 포함하는지 여부를 기준으로 검색을 수행합니다.
🫡 PageRequest
PageRequest는 페이징 처리를 위한 클래스입니다. 여기서는 첫 번째 페이지(0번째)에서 최대 10개의 결과를 반환하도록 설정합니다.
🥹 CriteriaQuery
CriteriaQuery는 Criteria와 PageRequest를 기반으로 Elasticsearch 쿼리를 구성하는 클래스입니다. 이 쿼리를 사용하여 Elasticsearch에서 검색을 수행합니다.
😎 search
elasticsearchOperations.search(query, SchoolDocument.class)는 정의된 쿼리를 사용하여 Elasticsearch에서 검색을 수행하고, 결과를 SchoolDocument 타입의 객체로 반환합니다.
🚍 내가 해당 방식을 적용하기까지의 과정
각각에 대한 부분을 작성을 하였고 사실 별거 없다.
내가 자동완성에 ElasticSearch를 사용한 이유는 자동완성 기능에 매우 적합하다. 그 이유는 데이터를 저장하면서 역색인구조를 사용해 각 단어와 문구의 위치를 저장하여 입력되는 검색에 대해 빠르게 결과를 할 수 있는 이유이다.
-> 역색인은 따로 추가적으로 공부하여 게시글을 작성하겠습니다.
엘라스틱 서치는 다양한 것들을 지원하며 다양한 예시를 아래에서 보여드리겠습니다.
✨ First. Edge N-gram 분석기를 설정해야하며 해당 분석기를 설정하는 방법이 있습니다.
해당 코드는 예시입니다.
PUT /schools
{
"settings": {
"analysis": {
"tokenizer": {
"edge_ngram_tokenizer": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20,
"token_chars": [
"letter"
]
}
},
"analyzer": {
"edge_ngram_analyzer": {
"type": "custom",
"tokenizer": "edge_ngram_tokenizer",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"school_name": {
"type": "text",
"analyzer": "edge_ngram_analyzer",
"search_analyzer": "standard"
}
}
}
}
만약에 진행한다면 위에 같은 방식으로 진행이 되었을 것이고 하지만 학교데이터는 어떤게 많이 사용될지 예측할 수 없으므로 사용자는 다양한 학교를 다닐 것을 예상하여 해당 방법으로 진행하지 않았습니다.
📚 Completion suggester 방법입니다.
Completeion suggester는 ElasticSearch에서 제공하는 또 다른 자동완성 기능이고 해당 방식으로 진행하려고 하니 많은 외국자료 및 국내자료가 @Deprecated되어 있어 해당 방식으로 진행하지 못하였습니다. 아마 적용이 된다면 구 버전 ElasticSearch일 것으로 판단됩니다.
😇 인덱스 생성
PUT /schools
{
"mappings": {
"properties": {
"school_name": {
"type": "completion"
}
}
}
}
🚴🏻♂️ 데이터 인덱싱
POST /schools/_doc/1
{
"school_name": "Springfield High School"
}
POST /schools/_doc/2
{
"school_name": "Spring Valley School"
}
POST /schools/_doc/3
{
"school_name": "Springside Chestnut Hill Academy"
}
🛞 자동완성 쿼리
POST /schools/_search
{
"suggest": {
"school-suggest": {
"prefix": "Spr",
"completion": {
"field": "school_name",
"size": 10
}
}
}
}
해당 방식은 ElasticSearch에 들어가서 인덱싱을 적용시켜 확인 할 수 있습니다.
하지만 저희는 Spring 서버에서 적용해야하기에 ElasticSearch Docs를 정처 없이 떠돌던 중 prefixQuery방식으로 하는 방법을 찾았습니다. 그렇게 해서 작성하게 된 코드는 위에 작성한 코드 입니다.
사실 솔직하게 말하면 데이터가 겨우 1만2천 건 밖에 되어 있지 않아 RDBMS를 사용하더라도 크게 문제 없었을 것으로 판단하였지만 앞으로 많은 자동완성기능을 이력서 부분에 추가해야하기에 ElasticSearch를 적용하였습니다.
해당 글에 부족한 부분이 많으니 참고하여 봐주셨으면 좋겠습니다.
'취준생 프로젝트' 카테고리의 다른 글
Jmeter 사용한 성능 분석 여행기 (맥북 설치 포함) (1) | 2024.11.27 |
---|---|
1부 itzip 프로젝트 이력서에 테스트 코드 TDD 적용기 (3) | 2024.11.27 |
docker-compose ELK 설치 (1) | 2024.08.14 |
WebClient를 사용한 커리어넷 학교 정보 API가져오기 (0) | 2024.08.08 |
Sping boot AWS bucket 업로드, 수정 , 삭제하기 (4) | 2024.07.23 |