Amenable
Amenable's Blog
Amenable
  • λΆ„λ₯˜ 전체보기 (189)
    • πŸ“‚ JAVA (87)
      • μ΄νŽ™ν‹°λΈŒ μžλ°” (65)
      • μ£Όμš” κ°œλ… (22)
    • πŸ“‚ 개발 μ„œμ  (22)
      • μ‹€μš©μ£Όμ˜ ν”„λ‘œκ·Έλž˜λ¨Έ (1)
      • 객체지ν–₯의 사싀과 μ˜€ν•΄ (2)
      • 클린 μ½”λ“œ (8)
      • ν•¨κ»˜ 자라기 (1)
      • 그림으둜 λ°°μš°λŠ” HTTP&Network Basic (10)
    • πŸ“‚ λ°μ΄ν„°λ² μ΄μŠ€ (8)
      • κ°œλ… (8)
      • λ¬Έμ œν’€μ΄ (0)
    • πŸ“‚ λ„€νŠΈμ›Œν¬ (14)
      • κ°œλ… (6)
      • 성곡과 μ‹€νŒ¨λ₯Ό κ²°μ •ν•˜λŠ” 1%의 λ„€νŠΈμ›Œν¬ 원리 (8)
    • πŸ“‚ μŠ€ν”„λ§ (13)
      • κΈ°λ³Έ κ°œλ… (13)
    • πŸ“‚ WEB (5)
    • πŸ“‚ 자료ꡬ쑰 (12)
      • κ°œλ… (2)
      • μ •λ ¬ (8)
      • 트리 (2)
    • πŸ“‚ μ•Œκ³ λ¦¬μ¦˜ (10)
      • μ΅œμ†Œμ‹ μž₯트리 (2)
      • μ΅œλ‹¨ 경둜 (2)
      • λ¬Έμžμ—΄ (2)
      • ETC (4)
    • πŸ“‚ μ•Œκ³ λ¦¬μ¦˜_λ¬Έμ œν’€μ΄ (4)
      • BOJ_λ°±μ€€ (4)
    • πŸ“‚ ν”„λ‘œκ·Έλž˜λ° (3)
    • πŸ“‚ DevOps (2)
      • 배포 (2)
    • πŸ“‚ ν›„κΈ° (8)
      • μš°μ•„ν•œ ν…Œν¬μ½”μŠ€(ν”„λ¦¬μ½”μŠ€) (4)
      • 2023λ…„ (3)
      • 2024λ…„ (1)
    • πŸ“‚ 회고 (1)
      • 2023λ…„ (1)

λΈ”λ‘œκ·Έ 메뉴

  • πŸš€ GitHub

ν‹°μŠ€ν† λ¦¬

hELLO Β· Designed By μ •μƒμš°.
Amenable

Amenable's Blog

μ—˜λΌμŠ€ν‹±μ„œμΉ˜(Elasticsearch) 적용 ν›„κΈ°
πŸ“‚ ν›„κΈ°/2023λ…„

μ—˜λΌμŠ€ν‹±μ„œμΉ˜(Elasticsearch) 적용 ν›„κΈ°

2023. 12. 8. 20:20

πŸ“™ 1. μ—˜λΌμŠ€ν‹±μ„œμΉ˜(Elasticsearch)λ₯Ό μ‚¬μš©ν•˜κ²Œ 된 계기

  ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μƒλŒ€μ μœΌλ‘œ 크기가 큰 동물 데이터(130만 건의 데이터)λ₯Ό μ‚¬μš©ν•  일이 μžˆμ—ˆλ‹€.

  ν•„μš”ν•œ μž‘μ—…μ€ 'λ™λ¬Όμ˜ 계측적 λΆ„λ₯˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” κ°’μ—μ„œ νŠΉμ • 계측이 μžˆλŠ” 동물을 μ‘°νšŒν•˜λŠ” 것'μ΄μ—ˆλ‹€. μ΄λŸ¬ν•œ κ³Όμ •μ—μ„œ μ–΄λ–»κ²Œ ν•˜λ©΄ μ‘°νšŒ μ‹œκ°„을 λ‹¨μΆ•μ‹œν‚¬ μˆ˜ μžˆμ„κΉŒ κ³ λ―Όν•˜μ˜€κ³  κ·Έ κ²°κ³Ό μ—˜λΌμŠ€ν‹±μ„œμΉ˜(Elasticsearch)λ₯Ό μ‚¬μš©ν•˜κ²Œ λ˜μ—ˆλ‹€.

  μž‘μ—…μ— λŒ€ν•΄μ„œ 쑰금 더 μžμ„Έν•˜κ²Œ μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž. μ›ν•˜λŠ” λ™μž‘μ€ 'λ™λ¬Όμ˜ 계측적 λΆ„λ₯˜(higherClassification)μ—μ„œ νŠΉμ • 계측(포유λ₯˜, μ–‘μ„œλ₯˜, μ‘°λ₯˜,...)이 μ‘΄μž¬ν•˜λŠ” 동물듀을 κ°€μ Έμ˜€λŠ” 것'이닀.

  λ°μ΄ν„°λŠ” μ•„λž˜μ™€ 같이 κ΅¬μ„±λ˜μ–΄ μžˆλ‹€.

{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Proboscidea; Elephantidae"
  ...
},
{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Rodentia; Mymorpha"
  ...
}

  λ§Œμ•½ Mammalia(포유λ₯˜)λΌλŠ” 계측을 ν¬ν•¨ν•˜κ³  μžˆλŠ” 동물을 κ°€μ Έμ˜¨λ‹€κ³  ν•˜λ©΄ μ•„λž˜ 2개의 데이터λ₯Ό λͺ¨λ‘ κ°€μ Έμ˜¬ 것이닀.

{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Proboscidea; Elephantidae"
  ...
},
{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Rodentia; Mymorpha"
  ...
}

  ν•˜μ§€λ§Œ, Elephantidae(코끼리과)λΌλŠ” 계측을 ν¬ν•¨ν•˜κ³  μžˆλŠ” 동물을 κ°€μ Έμ˜¨λ‹€κ³  ν•˜λ©΄, 2κ°œκ°€ μ•„λ‹Œ 1개의 λ°μ΄ν„°λ§Œ κ°€μ Έμ˜¬ 것이닀.


{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Proboscidea; Elephantidae"
  ...
},
{
  ...
  "higherClassification": "Animalia; Chordata; Vertebrata; Mammalia; Rodentia; Mymorpha"
  ...
}

  즉, 130만 건의 λ°μ΄ν„°μ—μ„œ νŠΉμ • 속성(λ™λ¬Όμ˜ 계측적 λΆ„λ₯˜, higherClassification)의 값을 λ‚˜νƒ€λ‚΄λŠ” λ¬Έμžμ—΄μ— νŠΉμ • λ¬Έμžμ—΄(포유λ₯˜, μ–‘μ„œλ₯˜, μ‘°λ₯˜,...)이 μžˆλŠ”μ§€ ν™•μΈν•˜κ³  κ·Έ 값을 가져와야 ν–ˆλ‹€.

  λ°μ΄ν„°μ—μ„œ μ›ν•˜λŠ” 값을 λΉ λ₯΄κ²Œ κ°€μ Έμ˜€κΈ° μœ„ν•΄ μ•„λž˜ 3κ°€μ§€ κΈ°μˆ μ„ κ³ λ €ν•΄ λ³΄μ•˜λ‹€.

 

πŸ“Œ 1. MySQL

  MySQL둜 μœ„μ˜ μž‘μ—…μ„ ν•˜κ²Œ λœλ‹€λ©΄ Full-Scan을 ν•œλ‹€λŠ” 문제점이 μžˆμ—ˆλ‹€.

  λ˜ν•œ, λ¬Έμžμ—΄μ—μ„œ νŠΉμ • λ¬Έμžκ°€ μ‘΄μž¬ν•˜λŠ”μ§€ μ•ŒκΈ° μœ„ν•΄ LIKE μ‚¬μš©ν•˜κ²Œ λœλ‹€. LIKEκ°€ λ™μž‘ν•˜κ²Œ 되면 Turbo Boyer-Moore μ•Œκ³ λ¦¬μ¦˜μ΄ μž‘λ™ν•˜κ²Œ λœλ‹€.

  κ³΅μ‹λ¬Έμ„œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄, LIKEλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 일반적으둜 μΈλ±μŠ€κ°€ κ±Έλ €μžˆλŠ” 경우 B-Treeλ₯Ό μ΄μš©ν•˜κ³ , κ·Έλ ‡μ§€ μ•Šμ€ κ²½μš°μ—λŠ” Turbo Boyer-μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•œλ‹€κ³  λ˜μ–΄μžˆλ‹€.

 

MySQL :: MySQL 8.0 Reference Manual :: 8.3.9 Comparison of B-Tree and Hash Indexes

8.3.9 Comparison of B-Tree and Hash Indexes Understanding the B-tree and hash data structures can help predict how different queries perform on different storage engines that use these data structures in their indexes, particularly for the MEMORY storage

dev.mysql.com

  Turbo Boyer-Moore에 λŒ€ν•œ λ‚΄μš©μ€ μ•„λž˜μ˜ 글을 μ°Έκ³ ν•˜μž.

 

Turbo-BM algorithm

The Turbo-BM algorithm is an amelioration of the Boyer-Moore algorithm. It needs no extra preprocessing and requires only a constant extra space with respect to the original Boyer-Moore algorithm. It consists in remembering the factor of the text that matc

www-igm.univ-mlv.fr

  μ΄λŸ¬ν•œ 사싀과 ν•¨κ»˜ μ‹œκ°„λ³΅μž‘λ„λ₯Ό 계산해 보면 O(λ°μ΄ν„°μ˜ 크기_130만 건) x O(λ¬Έμžμ—΄μ˜ 길이)κ°€ 되게 λœλ‹€.

 

πŸ“Œ 2. Apatch Hive

  Apatch Hiveλž€ κ΅¬μ‘°ν™”λœ 빅데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 μ‚¬μš©λ˜λ©΄ HiveQL을 μ΄μš©ν•˜μ—¬ νŽΈλ¦¬ν•˜κ²Œ ν•˜λ‘‘(λΆ„μ‚° 파일 μ‹œμŠ€ν…œ)을 μ΄μš©ν•  수 있게 ν•˜λŠ” 것이닀.

  HiveQL을 ν†΅ν•΄μ„œ 쑰회λ₯Ό μ‹€ν–‰ν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ λ§΅-λ¦¬λ“€μŠ€ μ–Έμ–΄λ‘œ λ³€ν™˜ν•˜λŠ” μž‘μ—…μ„ 거치기 λ•Œλ¬Έμ—, λ§΅κ³Ό λ¦¬λ“€μŠ€ κ°„μ˜ μ…”ν”Œλ§ μž‘μ—…μœΌλ‘œ μΈν•˜μ—¬ 속도가 λŠλ¦¬λ‹€λŠ” 단점이 μžˆλ‹€.

 

πŸ“Œ 3. Elasticsearch

  Elasticsearch(μ΄ν•˜ ES)λŠ” μ—­μΈλ±μŠ€(Inverted Index, 역색인)λ₯Ό μ΄μš©ν•œλ‹€. (ES에 λŒ€ν•œ μžμ„Έν•œ μ„€λͺ…은 μ•„λž˜μ— λ‚˜μ˜΅λ‹ˆλ‹€.)

  μ—­μΈλ±μŠ€λ₯Ό ν™œμš©ν•˜μ—¬ ν‚€μ›Œλ“œλ₯Ό 톡해 λ¬Έμ„œλ₯Ό μ°ΎλŠ”λ‹€. κ·Έλž˜μ„œ μš°λ¦¬κ°€ μ›ν•˜λŠ” 쑰회 μž‘μ—…μ΄ 맀우 λΉ λ₯΄λ‹€λŠ” μž₯점이 μžˆλ‹€. 

 

  3κ°€μ§€ κΈ°μˆ μ„ λΉ„κ΅λΆ„μ„ν•œ κ²°κ³Ό, ESκ°€ 'μƒλŒ€μ μœΌλ‘œ 큰 λ°μ΄ν„°μ—μ„œ νŠΉμ • λ¬Έμžμ—΄μ„ κ°€μ§„ 데이터λ₯Ό μ°ΎλŠ” μž‘μ—…'에 κ°€μž₯ μ μ ˆν•˜λ‹€κ³  μƒκ°ν•˜μ—¬ ESλ₯Ό μ“°κΈ°λ‘œ ν•˜μ˜€λ‹€. 

 

πŸ“™ 2. ES κ°œλ… & νŠΉμ§•

πŸ“Œ 1. κ°œλ…

  ESλŠ” Apache Lucene 기반의 μ˜€ν”ˆμ†ŒμŠ€ λΆ„μ‚° 검색 엔진이닀. (Apache Lucene은 λͺ¨λ“  κ²€μƒ‰μ—”μ§„μ˜ μ‹œμ΄ˆλΌκ³  ν•  수 μžˆλ‹€.)

  기본적으둜 데이터λ₯Ό μΈλ±μ‹±ν•˜μ—¬ μ €μž₯ν•˜κ³ , 검색, 집계 λ“±μ˜ κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€.

πŸ“Œ 2. νŠΉμ§•

  ES의 κ°€μž₯ 큰 νŠΉμ§•μ€ μš°λ¦¬κ°€ ν”νžˆ μ•„λŠ” 인덱슀(forward index)κ°€ μ•„λ‹Œ μ—­μΈλ±μŠ€(inverted index)λ₯Ό μ‚¬μš©ν•œλ‹€λŠ” 것이닀.

  인덱슀λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ μ•„λž˜μ™€ 같이 데이터가 μ €μž₯될 것이닀.

Document Words
λ¬Έμ„œ1 사과, λ°”λ‚˜λ‚˜, κ·€
λ¬Έμ„œ2 사과, μž₯λ―Έ
λ¬Έμ„œ3 사과, 곡, κ·€

  반면, μ—­μΈλ±μŠ€λ₯Ό μ΄μš©ν•œλ‹€λ©΄ μ•„λž˜μ™€ 같이 데이터가 μ €μž₯λœλ‹€.

Word Document
사과 λ¬Έμ„œ1, λ¬Έμ„œ2, λ¬Έμ„œ3
κ·€ λ¬Έμ„œ1, λ¬Έμ„œ3
λ°”λ‚˜λ‚˜ λ¬Έμ„œ1
μž₯λ―Έ λ¬Έμ„œ2
곡 λ¬Έμ„œ3

 

  귀을 κ°€μ§€κ³  μžˆλŠ” 데이터λ₯Ό κ°€μ Έμ˜¨λ‹€κ³  ν•΄λ³΄μž. 인덱슀λ₯Ό μ΄μš©ν•˜μ—¬ μ‘°νšŒν•˜λ©΄ λ‹€μŒκ³Ό 같이 ν…μŠ€νŠΈλ₯Ό ν•˜λ‚˜ν•˜λ‚˜ μ½μœΌλ©΄μ„œ 검색을 ν•  것이닀.

Document Words 검색(λΉ„κ΅ν•΄λ³΄λŠ” λ™μž‘) 쑰회(κ°€μ Έμ˜€λŠ” λ™μž‘)
λ¬Έμ„œ1 사과, λ°”λ‚˜λ‚˜, κ·€ O O
λ¬Έμ„œ2 사과, μž₯λ―Έ O X
λ¬Έμ„œ3 사과, 곡, κ·€ O O

  ν•˜μ§€λ§Œ, μ—­μΈλ±μŠ€λ₯Ό μ΄μš©ν•˜μ—¬ μ‘°νšŒν•˜λ©΄ ν…μŠ€νŠΈλ₯Ό ν•˜λ‚˜ν•˜λ‚˜ 읽지 μ•Šκ³ λ„ ν‚€μ›Œλ“œμ— ν•΄λ‹Ήν•˜λŠ” 값을 λ°”λ‘œ 얻을 수 μžˆλ‹€.

Word Document 검색(λΉ„κ΅ν•΄λ³΄λŠ” λ™μž‘) 쑰회(κ°€μ Έμ˜€λŠ” λ™μž‘)
사과 λ¬Έμ„œ1, λ¬Έμ„œ2, λ¬Έμ„œ3 X X
κ·€ λ¬Έμ„œ1, λ¬Έμ„œ3 O O
λ°”λ‚˜λ‚˜ λ¬Έμ„œ1 X X
μž₯λ―Έ λ¬Έμ„œ2 X X
곡 λ¬Έμ„œ3 X X

  μ΄λŸ¬ν•œ 이유둜 ESλ₯Ό μ΄μš©ν•˜λ©΄ λΉ λ₯Έ μ†λ„λ‘œ 쑰회λ₯Ό ν•  수 μžˆλ‹€.

 

πŸ“™ 3. 적용

  μŠ€ν”„λ§λΆ€νŠΈ ν™˜κ²½μ—μ„œ ESλ₯Ό μ μš©ν•˜μ˜€λ‹€. 'ES μ‚¬μš©μ„ μœ„ν•œ ν™˜κ²½ μ„ΈνŒ…, λ°μ΄ν„° μ‚½μž…, λ°μ΄ν„° μ‘°νšŒ'λΌλŠ” 3κ°€μ§€ λ‹¨κ³„λ₯Ό μ΄μš©ν•˜μ—¬ μ‚΄νŽ΄λ³΄μž.

πŸ“Œ 1. ES μ‚¬μš©μ„ μœ„ν•œ ν™˜κ²½ μ„ΈνŒ…

1. dependency μΆ”κ°€

dependencies {
  implementation 'org.springframework.data:spring-data-elasticsearch:4.2.2'
}

2. config μ„€μ •

@Configuration
@EnableElasticsearchRepositories(basePackageClasses = {Animal.class})
public class ElasticSearchConfig extends AbstractElasticsearchConfiguration {

    @Value("${elasticsearch.host}")
    private String host;

    @Value("${elasticsearch.port}")
    private int port;

    @Override
    public RestHighLevelClient elasticsearchClient() {
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(host + ":" + port)
                .build();
        return RestClients.create(clientConfiguration).rest();
    }
}

3. 객체 생성

@NoArgsConstructor
@Getter
public class Animal {

    @Id
    private Long id;
    private String continent;
    private String country;
    private String decimalLatitude;
    private String decimalLongitude;
    private String scientificName;
    private String family;
    private String genus;
    private String higherClassification;

    @Builder
    private Animal(Long id, String continent, String country, 
            String decimalLatitude, String decimalLongitude, String scientificName, 
            String family, String genus, String higherClassification) {
        this.id = id;
        this.continent = continent;
        this.country = country;
        this.decimalLatitude = decimalLatitude;
        this.decimalLongitude = decimalLongitude;
        this.scientificName = scientificName;
        this.family = family;
        this.genus = genus;
        this.higherClassification = higherClassification;
    }
}

4. Repository 생성

  JpaRepository와 μœ μ‚¬ν•œ λ°©λ²•μœΌλ‘œ ElasticRepositoryλ₯Ό μ‚¬μš©ν•˜μ—¬ Repositoryλ₯Ό λ§Œλ“€λ©΄ λœλ‹€.

public interface AnimalRepository extends ElasticsearchRepository<Animal, Long>, 
        CrudRepository<Animal, Long> {

    List<Animal> findByHigherClassificationContains(String country);
}

πŸ“Œ 2. 데이터 μ‚½μž…

  κΈ°μ‘΄ λ°μ΄ν„°λ² μ΄μŠ€μ— μžˆλŠ” 값을 μ΄μš©ν•˜μ—¬ ES에 값을 λ„£μ–΄μ£Όμ—ˆλ‹€.

public void addAnimalAtES(List<Animal> animals) {
    animalRepository.saveAll(animals);
}

πŸ“Œ 3. 데이터 쑰회

  λ‹€μŒκ³Ό 같이 νŠΉμ • 계측 값을 μ΄μš©ν•˜μ—¬ μ‘°νšŒν•œλ‹€.

public List<Animal> getAnimalsBy(String higherClass) {
    return AnimalRepository.findByHigherClassificationContains(higherClass);
}

 

πŸ“™ 4. κ²°κ³Ό

  λ³€κ²½ μ „ κ±Έλ¦° μ‹œκ°„(MySQL을 μ‚¬μš©ν•˜λŠ” 경우)κ³Ό λ³€κ²½ ν›„ κ±Έλ¦° μ‹œκ°„(ESλ₯Ό μ‚¬μš©ν•˜λŠ” 경우)은 λ‹€μŒκ³Ό κ°™λ‹€.

  λ³€κ²½ μ „(ms) λ³€κ²½ ν›„(ms)
포유λ₯˜ 1332.6 75.8
파좩λ₯˜ 1318.0 64.3
μ‘°λ₯˜ 1393.8 87.2
μ–‘μ„œλ₯˜ 1353.3 87.7
갑각λ₯˜ 1325.2 89.8
  λ³€κ²½ μ „(ms) λ³€κ²½ ν›„(ms)
전체 1346.3 81.9

 

  ESλ₯Ό ν™œμš©ν•˜μ—¬ κΈ°μ‘΄ λŒ€λΉ„(MySQL) μ•½ 16배의 κ°œμ„ λœ μ„±λŠ₯을 확인할 수 μžˆμ—ˆλ‹€. (5개의 μƒν™©μ— λŒ€ν•΄μ„œ κ°κ° 20λ²ˆμ”©, μ΄ 100번의 λΉ„ꡐλ₯Ό μ§„ν–‰ν•œ κ²°κ³Όμž…λ‹ˆλ‹€.)

 

ν•΄λ‹Ή 글은
Yoon Sungλ‹˜μ˜ 'Mysql Like λ™μž‘ 방식',
MySQL κ³΅μ‹λ¬Έμ„œ '8.3.9 Comparision of B-Tree and Hash Indexes',
'Turbo-BM algorithm',
yeomyalooλ‹˜μ˜ 'μ‡Όν•‘λͺ° λ§Œλ“€κΈ° ν”„λ‘œμ νŠΈ - μ—˜λΌμŠ€ν‹±μ„œμΉ˜(elasticsearch)와 μŠ€ν”„λ§λΆ€νŠΈ μ—°λ™ν•΄λ³΄μž',
μ˜λ‹ˆλ‹˜μ˜ '[spring boot] μŠ€ν”„λ§λΆ€νŠΈμ—μ„œ elasticsearch μ‹œμž‘ν•˜κΈ°',
msjeong97λ‹˜μ˜ 'Elasticsearchλž€',
justdoIT0703λ‹˜μ˜ '[Elastic Search] μ—˜λΌμŠ€ν‹±μ„œμΉ˜λž€? 2. μ—­ 색인(Inverted Index)',
제이온(Jayon)λ‹˜μ˜ '[λ°μ΄ν„°λ² μ΄μŠ€] μ—­μƒ‰μΈμ΄λž€?',
을 μ°Έκ³ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

 

'πŸ“‚ ν›„κΈ° > 2023λ…„' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

ν…ŒμŠ€νŠΈ 컀버리지 100% 달성 ν›„κΈ°  (2) 2023.12.07
νŽ˜μ–΄ν”„λ‘œκ·Έλž˜λ°(Pair Programming) ν›„κΈ°  (0) 2023.05.28
    'πŸ“‚ ν›„κΈ°/2023λ…„' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
    • ν…ŒμŠ€νŠΈ 컀버리지 100% 달성 ν›„κΈ°
    • νŽ˜μ–΄ν”„λ‘œκ·Έλž˜λ°(Pair Programming) ν›„κΈ°
    Amenable
    Amenable
    CS, μžλ°”, 자료ꡬ쑰, μ•Œκ³ λ¦¬μ¦˜, μŠ€ν”„λ§, μŠ€ν”„λ§ λΆ€νŠΈμ— ν•΄λ‹Ήν•˜λŠ” κ°œλ°œμ— κ΄€ν•œ λ‚΄μš©μ„ κ³΅μœ ν•©λ‹ˆλ‹€.

    ν‹°μŠ€ν† λ¦¬νˆ΄λ°”