words
├── README.md
├── docker-compose.yaml
├── requirements.txt
├── setup.py
├── test
│ ├── __init__.py
│ ├── test_delete_service.py
│ ├── test_post_service.py
│ └── test_search_service.py
├── word
├── __init__.py
├── cli.py
├── commands
│ ├── __init__.py
│ ├── cmd_cli.py
│ └── utils.py
├── config.py
├── model
│ ├── __init__.py
│ ├── dictionary.py
├── service
│ ├── __init__.py
│ ├── delete_service.py
│ ├── post_service.py
│ └── search_service.py
└── utils.py
docker compose up -d
brew install virtualenv
virtualenv venv
source venv/bin/activate
pip install .
Post wordsapi_sample.json
word cli post {file path}
Delete index
word cli delete
- 명령어를 실행하면 y/N로 한번 더 확인한다.
Search word or example sentences
word: word cli search {word}
example sentence: word cli search -e {sentence} -s {size}
- size는 검색 결과의 단어수 이다. 기본 설정은 2로 되어 있다.
- post전 또는 delete이후에 실행시 NotFoundError("Post sample words before search")가 발생한다.
Post의 성능 향상
post의 성능 향상을 위해, bulk request를 사용했습니다.
bulk의 chuck size가 500이기 때문에 500을 기준으로 benchmark를 진행하였습니다.
Size 300: 1 round - 345.5526201725006 sec | 2 round - 343.08479285240173 sec
|
Size 500: 1 round - 251.180734872818 sec | 2 round - 251.35249996185303 sec
|
Size 1000: 1 round - 254.36213183403015 sec | 2 round - 254.26697492599487 sec
|
Size 2000: 1 round - 258.06533885002136 sec | 2 round - 259.1686267852783 sec
Post를 200번 요청하여 결과를 받기 까지의 시간.
결과적으로 batch size를 500으로 설정하였을 때 최적의 결과를 보여준다.
Size 500: 1 round - 244.11668300628662 sec | 2 round - 243.90434217453003 sec
Post를 200번 요청하여 결과를 받기 까지의 시간.
index의 mappings을 사용한 값을 보여준다. 이전의 값과 비교하였을 때, 향상된 성능을 보여준다.
Search의 성능 향상
1. shard
과2. ASCII folding token filter
의 benchmark의 각 round는 search를 1,000번 요청한 결과값3. Prefix length
과4. Multi Queries
의 benchmark의 각 round는 search를 10,000번 요청한 결과값
한 번에 많은 양의 request를 받았을 때, shard의 개수가 검색 성능 향상에 영향을 줄 수 있다.
Shard num: 1 shard num: 3
1 round 3.4565341472625732 sec 1.763411045074463 sec
2 round 3.7890970706939697 sec 1.7218880653381348 sec
3 round 3.8013930320739746 sec 1.8412392139434814 sec
4 round 4.029897928237915 sec 2.785281181335449 sec
5 round 4.308093786239624 sec 2.243682861328125 sec
6 round 3.677070140838623 sec 2.0040361881256104 sec
7 round 3.4081621170043945 sec 1.9161927700042725 sec
8 round 2.8633573055267334 sec 2.3039710521698 sec
9 round 3.09560489654541 sec 2.0648908615112305 sec
10 round 4.734143972396851 sec 2.4587149620056152 sec
total: 37.163354396820067 sec total: 21.10330820083618 sec
search를 1000번 요청하여 결과를 받기 까지의 시간.
(W/O ASCII folding) (With ASCII folding)
1 round 3.4565341472625732 sec 1.6874911785125732 sec
2 round 3.7890970706939697 sec 1.5512290000915527 sec
3 round 3.8013930320739746 sec 1.5330629348754883 sec
4 round 4.029897928237915 sec 1.541114091873169 sec
5 round 4.308093786239624 sec 1.5603041648864746 sec
6 round 3.677070140838623 sec 1.445824146270752 sec
7 round 3.4081621170043945 sec 1.8313138484954834 sec
8 round 2.8633573055267334 sec 2.085002899169922 sec
9 round 3.09560489654541 sec 2.0446016788482666 sec
10 round 4.734143972396851 sec 2.644033908843994 sec
total: 37.163354396820067 sec total: 17.923977851867676 sec
search를 1,000번 요청하여 결과를 받기 까지의 시간.
검색 대상의 단어와 예문은 영어로 한정된다. 검색 대상이 영어로 한정될 경우 ASCII Folding을 적용할 경우 검색의 성능을 향상할 수 있다. Benchmark를 확인하면 오른쪽의 ASCII Folding이 적용된 검색이 10개의 round에서 좋은 성능을 보여준다.
elasticsearch에 document를 post 할 때 ASCII Folding analyzer를 검색 대상에 추가해 주면 된다.
folding_analyzer = analyzer(
'folding_analyzer',
tokenizer="standard",
filter=["lowercase", "asciifolding"]
)
class Dictionary(Document):
word: Text(analyzer=folding_analyzer)
definitions: Text()
syllables: Text()
pronunciation: Text()
rhyme_patterns: Text()
frequency: Text()
letters: Integer()
sounds: Integer()
examples: list[Text(analyzer=folding_analyzer)]
elasticsearch_dsl을 사용하여 작성한 document에 검색 대상이 되는 examples과 word에 analyzer를 추가한 모습이다.
<prefix_length: None> <prefix_length: 1> <prefix_length: 2>
1 round 28.594666957855225 sec 34.19754695892334 sec 43.60235285758972 sec
2 round 47.86689209938049 sec 46.341793060302734 sec 43.065855979919434 sec
3 round 46.53716516494751 sec 44.98031401634216 sec 43.949942111968994 sec
4 round 50.50426983833313 sec 45.391807079315186 sec 44.561277866363525 sec
5 round 47.29262185096741 sec 45.3971471786499 sec 43.950685024261475 sec
6 round 48.702868938446045 sec 45.21590614318848 sec 44.106505155563354 sec
7 round 49.00595021247864 sec 45.836780071258545 sec 45.144521951675415 sec
8 round 50.969626665115356 sec 44.66949677467346 sec 44.29913592338562 sec
9 round 49.00327396392822 sec 44.80926203727722 sec 44.28098392486572 sec
10 round 49.5166962146759 sec 45.23629808425903 sec 44.36857509613037 sec
total: 467.99403190612793 sec total: 442.07635140419006 sec total: 441.32983589172363 sec
각각의 round는 search를 10,000번 요청하여 결과를 받기 까지의 시간.
검색 성을 향상할 수 있는 또능 다른 방법은, prefix 옵션을 사용하는 것이다. 대부분의 오타는 단어의 중간 또는 마지막 부분에서 발생한다. 첫 단어부터 오타가 발생하는 경우는 거 없다. Benchmark는 prefix의 값을 다르게 설정하였을의 때 나오는 차이를 보여준다.
<Multi Queries> <Match - Fuzzyness>
1 round 25.279136896133423 sec 43.60235285758972 sec
2 round 48.654414892196655 sec 43.065855979919434 sec
3 round 50.0985381603241 sec 43.949942111968994 sec
4 round 51.193500995635986 sec 44.561277866363525 sec
5 round 49.93040609359741 sec 43.950685024261475 sec
6 round 50.95412802696228 sec 44.106505155563354 sec
7 round 49.68225812911987 sec 45.144521951675415 sec
8 round 50.037113904953 sec 44.29913592338562 sec
9 round 49.23568892478943 sec 44.28098392486572 sec
10 round 50.3095269203186 sec 44.36857509613037 sec
total: 475.37471294403076 sec total: 441.32983589172363 sec
각각의 round는 search를 10,000번 요청하여 결과를 받기 까지의 시간.
<Multi Queries> <Match - Fuzzyness>
max_score: 36.26639, max_score: 9.066598
hits: hits:
-score: 36.26639, -score: 9.066598
-source: -source:
-word: apple, -word: apple
-score: 27.506413, -score: 6.876603
-source: -source:
-word: apple-polisher -word: apple-polisher
왼쪽은 Multi Queries를 사용하여 apple을 검색한 결과이고, 오른쪽은 match를 이용하여 apple을 검색한 결과이다. 검색의 속도에서는 오른쪽의 match가 좋은 성능을 보여 준다. 또한 두 개의 검색 모두 apple을 가장 연관된 단어로 식별할 수 있었다. 하지만 score에서 큰 차이를 보인다.
"match": | "match": | "match_phrase":
key: | key: | key:
"query": value, | "query": value, | "query": value,
"fuzziness": "auto", | "fuzziness": "auto", | "boost": 2
'fuzzy_transpositions': True, | 'fuzzy_transpositions': True, |
"prefix_length": 1, | "prefix_length": 1, |
| "operator": "and" |
| |
조건 1 조건 2 조건 3
Multi Queries에서 사용된 조건이다. match를 위해 사용된 조건은 1번이었지만, multi queries에서는 1번, 2번, 3번 조건이 적용되었다. 추가된 조건을 통하여, 단어의 score에 가중치를 부여할 수 있게 되었으며, 검색의 정확도 향상을 기대할 수 있다.
post의 성능 향상을 위해 mappings을 사용하였으며, search 성능 향상의 위해서, ascii folding, prefix lengh, and multi queries를 사용하였다.
elasticsearch에서 score를 계산하기 위해 tf/idf를 사용한다.
Term frequency(tf)는 해당 다큐먼트에 검색한 단어의 빈도수를 의미한다.
Inverse Document frequency(idf)는 전체 다큐먼트 중 단어가 등장하는 빈도의 역을 의미한다. (전체의 다큐먼트에서 빈번하게 등장하는 단어의 가중치를 낮추기 위한 용도)
term frequency가 클수록, document frequency가 작을수록 score는 커지게 된다.
Field length 또한 score에 영향을 준다. 전체 다큐먼트에서 검색한 단어가 차지하는 비율이 클수록 score에 가중치가 부여된다.
4. Multi Queries
benchmark를 보면, best search engin score와 performance의 관계를 알 수 있다. 검색을 정확하게 하기 위해서 다양한 조건을 추가할 때
performance는 나빠진다. 반대로 적은 조건으로 검색을 수행했을 때 performance는 좋아진다. 결국, 정확성과 속도는 trade-off 관계이다.