Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 5개 있습니다.)
개발 환경 구성: 392. 윈도우 환경에서 curl.exe를 이용한 elasticsearch 6.x 기본 사용법
; https://www.sysnet.pe.kr/2/0/11663

개발 환경 구성: 393. 윈도우 환경에서 elasticsearch의 한글 형태소 분석기 설치
; https://www.sysnet.pe.kr/2/0/11664

개발 환경 구성: 394. 윈도우 환경에서 elasticsearch의 한글 블로그 검색 인덱스 구성
; https://www.sysnet.pe.kr/2/0/11669

.NET Framework: 791. C# - ElasticSearch를 위한 Client 라이브러리 제작
; https://www.sysnet.pe.kr/2/0/11676

개발 환경 구성: 507. Elasticsearch 6.6부터 기본 추가된 한글 형태소 분석기 노리(nori) 사용법
; https://www.sysnet.pe.kr/2/0/12309




Elasticsearch 6.6부터 기본 추가된 한글 형태소 분석기 노리(nori) 사용법

예전에는,

윈도우 환경에서 elasticsearch의 한글 형태소 분석기 설치
; https://www.sysnet.pe.kr/2/0/11664

한글 형태소 분석기 때문에 윈도우의 경우 최신 버전의 elasticsearch를 사용하고 싶어도 6.1.1로 고정했어야 하는 제약이, 이제는 6.6부터 elasticsearch 자체에서 제공하므로 마음껏 최신 버전 사용을 사용할 수 있습니다.

6.7.2 노리 (nori) 한글 형태소 분석기
; https://esbook.kimjmin.net/06-text-analysis/6.7-stemming/6.7.2-nori

자, 그럼 7.9 버전의 Elasticsearch로 클러스터도 구성해 보았으니,

Windows - 단일 머신에서 단일 바이너리로 여러 개의 ElasticSearch 노드를 실행하는 방법
; https://www.sysnet.pe.kr/2/0/12308

이참에 Nori도 설치해 보겠습니다. 방법이 매우 간단한데, "6.7.2 노리 (nori) 한글 형태소 분석기" 글에 나온 데로 Nori 플러그인을 설치하고,

D:\elk\elasticsearch> .\bin\elasticsearch-plugin install analysis-nori
-> Installing analysis-nori
-> Downloading analysis-nori from elastic
[=================================================] 100%
-> Installed analysis-nori

// 제거
// .\bin\elasticsearch-plugin remove analysis-nori

elasticsearch를 재시작하면 로드 도중 다음과 같은 메시지를 볼 수 있습니다.

[2020-09-02T11:07:48,023][INFO ][o.e.p.PluginsService     ] [TESTPC] loaded plugin [analysis-nori]




인덱스에 적용하기 전, 자신의 목적에 맞게 토큰을 잘 구획하는지는 다음과 같은 명령어로 확인할 수 있습니다.

curl -X POST "http://localhost:9200/_analyze" -H "Content-Type: application/json" -d "{ \"tokenizer\": \"nori_tokenizer\", \"text\": \"논쟁이 주를 이룹니다.\" }"

{"tokens":[{"token":"논쟁","start_offset":0,"end_offset":2,"type":"word","position":0},{"token":"이","start_offset":2,"end_offset":3,"type":"word","position":1},{"token":"주","start_offset":4,"end_offset":5,"type":"word","position":2},{"token":"를","start_offset":5,"end_offset":6,"type":"word","position":3},{"token":"이루","start_offset":7,"end_offset":11,"type":"word","position":4},{"token":"ㅂ니다","start_offset":7,"end_offset":11,"type":"word","position":5}]}


curl -X POST "http://localhost:9200/_analyze" -H "Content-Type: application/json" -d "{ \"tokenizer\": \"nori_tokenizer\", \"text\": \"동해물과 백두산이\" }"

{"tokens":[{"token":"동해","start_offset":0,"end_offset":2,"type":"word","position":0},{"token":"물","start_offset":2,"end_offset":3,"type":"word","position":1},{"token":"과","start_offset":3,"end_offset":4,"type":"word","position":2},{"token":"백두","start_offset":5,"end_offset":7,"type":"word","position":3},{"token":"산","start_offset":7,"end_offset":8,"type":"word","position":4},{"token":"이","start_offset":8,"end_offset":9,"type":"word","position":5}]}


보는 바와 같이, 기본 nori_tokenizer는 너무 세세하게 토큰을 나누기 때문에 일반적인 목적으로는 맞지 않습니다. 대신, "decompound_mode"의 옵션을 "none"으로 살짝 조정해 주면,

curl -X POST "http://localhost:9200/_analyze" -H "Content-Type: application/json" -d "{ \"tokenizer\": { \"type\": \"nori_tokenizer\", \"decompound_mode\": \"none\" }, \"text\": \"논쟁이 주를 이룹니다.\" }"

{"tokens":[{"token":"논쟁","start_offset":0,"end_offset":2,"type":"word","position":0},{"token":"이","start_offset":2,"end_offset":3,"type":"word","position":1},{"token":"주","start_offset":4,"end_offset":5,"type":"word","position":2},{"token":"를","start_offset":5,"end_offset":6,"type":"word","position":3},{"token":"이룹니다","start_offset":7,"end_offset":11,"type":"word","position":4}]}


curl -X POST "http://localhost:9200/_analyze" -H "Content-Type: application/json" -d "{ \"tokenizer\": { \"type\": \"nori_tokenizer\", \"decompound_mode\": \"none\" }, \"text\": \"동해물과 백두산이\" }"

{"tokens":[{"token":"동해","start_offset":0,"end_offset":2,"type":"word","position":0},{"token":"물","start_offset":2,"end_offset":3,"type":"word","position":1},{"token":"과","start_offset":3,"end_offset":4,"type":"word","position":2},{"token":"백두 산","start_offset":5,"end_offset":8,"type":"word","position":3},{"token":"이","start_offset":8,"end_offset":9,"type":"word","position":4}]}


여전히 "동해물"을 "동해" + "물"로, "백두산"을 "백두 산"으로 토큰을 나누는 것이 좀 마음에 안 들지만... 기본 모드였던 "discard"보다는 그나마 낫고 (별다른 대안이 없으므로) "none"으로 설정하는 것이 최선일 듯합니다.




tokenizer의 옵션 값이 결정되었으면 이제 인덱스에 반영해 보겠습니다. 다음의 글에 따라,

4.2 CRUD - 입력, 조회, 수정, 삭제
; https://esbook.kimjmin.net/04-data/4.2-crud

간단하게 "html_strip"과 "lowercase" 필터가 함께 적용된 tokenizer로 인덱스를 생성하고,

c:\temp> curl -XPUT "http://localhost:9200/my_org/" -H "Content-Type: application/json" -d "{ \"settings\":{ \"analysis\":{ \"analyzer\":{ \"nori_analyzer\": { \"tokenizer\": \"nori_tokenizer\", \"decompound_mode\": \"none\", \"char_filter\":[ \"html_strip\" ], \"filter\": [ \"lowercase\" ] } } } } }"

{"acknowledged":true,"shards_acknowledged":true,"index":"my_org"}

문서 구조를 정의한 다음,

c:\temp> curl -XPUT "http://localhost:9200/my_org/_mapping" -H "Content-Type: application/json" -d "{ \"properties\" : { \"name\" : {\"type\" :  \"text\", \"index\" : \"false\"}, \"age\" : {\"type\" : \"integer\"}, \"address\" : {\"type\" : \"text\", \"analyzer\": \"nori_analyzer\" }, \"registered\" : {\"type\" : \"date\"} } }"

{"acknowledged":true}

샘플 데이터를 넣으면,

/* doc_data1.json
{
    "name": "tester1",
    "age": 16,
    "address": "동해물과 백두산이 <h>스키마를</h>",
    "registered": "2017-04-29T10:16:00"
}
*/

/* doc_data2.json
{
    "name": "tester2",
    "age": 15,
    "address": "<span title='test'>김이지 Shine</span>",
    "registered": "2017-04-29T10:16:00"
}
*/

C:\temp> curl -XPUT "http://localhost:9200/my_org/_doc/1" -H "Content-Type: application/json" -d @doc_data1.json
{"_index":"my_org","_type":"_doc","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":2,"failed":0},"_seq_no":0,"_primary_term":1}

C:\temp> curl -XPUT "http://localhost:9200/my_org/_doc/2" -H "Content-Type: application/json" -d @doc_data2.json
{"_index":"my_org","_type":"_doc","_id":"2","_version":1,"result":"created","_shards":{"total":2,"successful":2,"failed":0},"_seq_no":1,"_primary_term":1}

이제 다음과 같이 검색할 수 있습니다.

C:\temp> curl -XGET "http://localhost:9200/my_org/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"address\": \"동해물\" } } }"

{"took":12,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":0.5753642,"hits":[{"_index":"my_org","_type":"_doc","_id":"1","_score":0.5753642,"_source":{  "name" : "tester", "age": 16, "address": "동해물과 백두산이 <h>스키마를</h>", "registered":"2017-04-29T10:16:00" }}]}}

그런데, "서해물"로도 검색이 되는군요. ^^;

C:\temp> curl -XGET "http://localhost:9200/my_org/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"address\": \"서해물\" } } }"
{"took":3,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":0.2876821,"hits":[{"_index":"my_org","_type":"_doc","_id":"1","_score":0.2876821,"_source":{  "name" : "tester", "age": 16, "address": "동해물과 백두산이 <h>스키마를</h>", "registered":"2017-04-29T10:16:00" }}]}}

다행히, "서해"로는 검색이 안 되고.

C:\temp> curl -XGET "http://localhost:9200/my_org/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"address\": \"서해\" } } }"
{"took":2,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 8/15/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 91  92  93  94  95  96  97  98  99  100  101  102  103  [104]  105  ...
NoWriterDateCnt.TitleFile(s)
11365정성태11/25/201722089오류 유형: 429. 이벤트 로그 - User Policy could not be updated successfully
11364정성태11/24/201724779사물인터넷: 11. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 마우스로 쓰는 방법 (절대 좌표) [2]
11363정성태11/23/201724714사물인터넷: 10. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 마우스 + 키보드로 쓰는 방법 (두 번째 이야기)
11362정성태11/22/201720411오류 유형: 428. 윈도우 업데이트 KB4048953 - 0x800705b4 [2]
11361정성태11/22/201723381오류 유형: 427. 이벤트 로그 - Filter Manager failed to attach to volume '\Device\HarddiskVolume??' 0xC03A001C
11360정성태11/22/201723847오류 유형: 426. 이벤트 로그 - The kernel power manager has initiated a shutdown transition.
11359정성태11/16/201723112오류 유형: 425. 윈도우 10 Version 1709 (OS Build 16299.64) 업그레이드 시 발생한 문제 2가지
11358정성태11/15/201728115사물인터넷: 9. Visual Studio 2017에서 Raspberry Pi C++ 응용 프로그램 제작 [1]
11357정성태11/15/201728575개발 환경 구성: 336. 윈도우 10 Bash 쉘에서 C++ 컴파일하는 방법
11356정성태11/15/201730131사물인터넷: 8. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 마우스 + 키보드로 쓰는 방법 [4]
11355정성태11/15/201725318사물인터넷: 7. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 마우스로 쓰는 방법 [2]파일 다운로드2
11354정성태11/14/201730154사물인터넷: 6. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 키보드로 쓰는 방법 [8]
11353정성태11/14/201727139사물인터넷: 5. Raspberry Pi Zero(OTG)를 다른 컴퓨터에 연결해 가상 이더넷 카드로 쓰는 방법 [1]
11352정성태11/14/201723466사물인터넷: 4. Samba를 이용해 윈도우와 Raspberry Pi간의 파일 교환 [1]
11351정성태11/7/201726365.NET Framework: 698. C# 컴파일러 대신 직접 구현하는 비동기(async/await) 코드 [6]파일 다운로드1
11350정성태11/1/201722432디버깅 기술: 108. windbg 분석 사례 - Redis 서버로의 호출을 기다리면서 hang 현상 발생
11349정성태10/31/201723097디버깅 기술: 107. windbg - x64 SOS 확장의 !clrstack 명령어가 출력하는 Child SP 값의 의미 [1]파일 다운로드1
11348정성태10/31/201719285디버깅 기술: 106. windbg - x64 역어셈블 코드에서 닷넷 메서드 호출의 인자를 확인하는 방법
11347정성태10/28/201723066오류 유형: 424. Visual Studio - "클래스 다이어그램 보기" 시 "작업을 완료할 수 없습니다. 해당 인터페이스를 지원하지 않습니다." 오류 발생
11346정성태10/25/201719712오류 유형: 423. Windows Server 2003 - The client-side extension could not remove user policy settings for 'Default Domain Policy {...}' (0x8007000d)
11338정성태10/25/201717297.NET Framework: 697. windbg - SOS DumpMT의 "BaseSize", "ComponentSize" 값에 대한 의미파일 다운로드1
11337정성태10/24/201719846.NET Framework: 696. windbg - SOS DumpClass/DumpMT의 "Vtable Slots", "Total Method Slots", "Slots in VTable" 값에 대한 의미파일 다운로드1
11336정성태10/20/201721130.NET Framework: 695. windbg - .NET string의 x86/x64 메모리 할당 구조
11335정성태10/18/201719916.NET Framework: 694. 닷넷 - <Module> 클래스의 용도
11334정성태10/18/201720645디버깅 기술: 105. windbg - k 명령어와 !clrstack을 조합한 호출 스택을 얻는 방법
11333정성태10/17/201719996오류 유형: 422. 윈도우 업데이트 - Code 9C48 Windows update encountered an unknown error.
... 91  92  93  94  95  96  97  98  99  100  101  102  103  [104]  105  ...