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의 한글 블로그 검색 인덱스 구성

지난 글에서 elasticsearch의 간단한 사용법을 알아봤는데요,

윈도우 환경에서 curl.exe를 이용한 elasticsearch 6.x 기본 사용법
; https://www.sysnet.pe.kr/2/0/11663

이번에는 그것을 이용해 블로그 글을 검색하는 환경을 구성해 보겠습니다. 우선, 이전 글에 따라 한글 검색을 도와주는 플러그인은 설치해야 합니다.

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

그 외에 블로그의 특성상 html 태그가 들어갈 것이므로 "openkoreantext-analyzer"를 기본으로 사용할 수는 없고, 다음과 같이 "html_strip" 필터를 추가로 구성해 analyzer를 만들어야 합니다.

{
    "settings": {
        "analysis": {
            "analyzer": {
                "blogtext_analyzer": {
                    "type": "custom",
                    "tokenizer": "openkoreantext-tokenizer",
                    "char_filter": [
                        "html_strip",
                        "openkoreantext-normalizer"
                    ],
                    "filter": [
                        "openkoreantext-stemmer",
                        "openkoreantext-redundant-filter"
                    ]
                }
            }
        }
    }
}

편의상 위의 내용을 settings.json 파일로 저장하고 다음과 같이 명령을 내리면 인덱스가 생성됩니다.

curl -XDELETE "http://localhost:9200/my_blog/"

curl -XPUT "http://localhost:9200/my_blog/" -H "Content-Type: application/json" -d "@settings.json"

또는 불편을 감수하고 다음과 같이 명령을 내리면 됩니다.

curl -XPUT "http://localhost:9200/my_blog/" -H "Content-Type: application/json" -d "{ \"settings\": { \"analysis\": { \"analyzer\": { \"blogtext_analyzer\": { \"type\": \"custom\", \"tokenizer\": \"openkoreantext-tokenizer\", \"char_filter\": [ \"html_strip\", \"openkoreantext-normalizer\" ], \"filter\": [ \"lowercase\", \"openkoreantext-stemmer\", \"openkoreantext-redundant-filter\" ] } } } } }"

사용자 정의 구성으로 blogtext_analyzer를 생성했으니, 이제 Type 정의에서 다음과 같이 적용할 수 있습니다.

{
    "articles": {
        "properties": {
            "writer": {
                "type": "text",
                "index": "false"
            },
            "wid": { "type": "integer" },
            "contents": {
                "type": "text",
                "analyzer": "blogtext_analyzer"
            },
            "registered": { "type": "date" }
        }
    }
}

위의 내용을 "articles.json" 파일로 저장하고 다음과 같이 명령을 내리거나,

curl -XPUT "http://localhost:9200/my_blog/articles/_mapping" -H "Content-Type: application/json" -d "@articles.json"

인라인으로 -d 옵션을 이용해 모두 써줘도 됩니다.

curl -XPUT "http://localhost:9200/my_blog/articles/_mapping" -H "Content-Type: application/json" -d "{ \"articles\" : { \"properties\" : {  \"writer\" : {\"type\" : \"text\", \"index\" : \"false\"}, \"wid\" : {\"type\" : \"integer\"}, \"contents\" : {\"type\" : \"text\", \"analyzer\": \"blogtext_analyzer\" }, \"registered\" : {\"type\" : \"date\"} } } }"

정상적으로 타입이 생성되었는지 Type 정의를 확인하고,

curl -XGET "http://localhost:9200/my_blog/articles/_mapping?pretty"

데이터 몇 개를 넣은 다음,

curl -XPUT "http://localhost:9200/my_blog/articles/1" -H "Content-Type: application/json" -d 
"{ 
    "name" : "tester", 
    "wid": 16, 
    "contents": "^gacutil.exe^를 실행해 ^<a href='dotnet'^>닷넷^</a^> DLL을 GAC에 등록하려 할 때 다음과 같은 식의 오류가 발생한다면?", 
    "registered":"2017-04-29T10:16:00" 
}"

curl -XPUT "http://localhost:9200/my_blog/articles/2" -H "Content-Type: application/json" -d 
"{ 
    "name" : "tester", 
    "wid": 17, 
    "contents": "한국어를 처리하는 예시입니닼ㅋㅋ", 
    "registered":"2017-04-29T10:16:00" 
}"

curl -XPUT "http://localhost:9200/my_blog/articles/3" -H "Content-Type: application/json" -d
"{ 
    "name" : "tester", 
    "wid": 17, 
    "contents": "테스트 이미지^<img alt=\\"test\\" ^>입니다.", 
    "registered":"2017-04-29T10:16:00" 
}"

curl -XPUT "http://localhost:9200/my_blog/articles/1" -H "Content-Type: application/json" -d "{ \"name\" : \"tester\", \"wid\": 16, \"contents\": \"^<b^>gacutil.exe^</b^>를 실행해 ^<a href='dotnet'^>닷넷^</a^> DLL을 GAC에 등록하려 할 때 다음과 같은 식의 오류가 발생한다면?\", \"registered\":\"2017-04-29T10:16:00\" }"

curl -XPUT "http://localhost:9200/my_blog/articles/2" -H "Content-Type: application/json" -d "{ \"name\" : \"tester\", \"wid\": 17, \"contents\": \"한국어를 처리하는 예시입니닼ㅋㅋ\", \"registered\":\"2017-04-29T10:16:00\" }"

curl -XPUT "http://localhost:9200/my_blog/articles/3" -H "Content-Type: application/json" -d "{ \"name\" : \"tester\", \"wid\": 18, \"contents\": \"테스트 이미지^<img alt=\\\"test\\\" ^>입니다.\", \"registered\":\"2017-04-29T10:16:00\" }"

검색 쿼리를 날려볼 수 있습니다.

curl -XGET "http://localhost:9200/my_blog/articles/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"contents\": \"gacutil\" } } }"

{"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":1,"max_score":0.2876821,"hits":[{"_index":"my_blog","_type":"articles","_id":"1","_score":0.2876821,"_source":{ "name" : "tester", "wid": 16, "contents": "<b>gacutil.exe</b>를 실행해 <a href='dotnet'>닷넷</a> DLL을 GAC에 등록하려 할 때 다음과 같은 식의 오 류가 발생한다면?", "registered":"2017-04-29T10:16:00" }}]}}

html_strip 필터를 적용했기 때문에 html 태그 내에 있던 내용은 검색되지 않습니다.

curl -XGET "http://localhost:9200/my_blog/articles/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"contents\": \"href\" } } }"

{"took":0,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}

html_strip이 좋긴 한데, 아쉽게도 img의 alt 태그와 같은 내용에 대한 배려가 없군요. ^^

curl -XGET "http://localhost:9200/my_blog/articles/_search" -H "Content-Type: application/json" -d "{ \"query\": { \"match\": { \"contents\": \"test\" } } }"

{"took":0,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}




curl.exe에서 HTML에 대한 인코딩이 잘못되면 다음과 같이 황당한 오류가 발생합니다.

c:\temp> curl -XPUT "http://localhost:9200/my_blog/articles/5" -H "Content-Type: application/json" -d "{ \"name\" : \"tester\", \"wid\": 17, \"address\": \"한국어를 <b>처리</b> 예시\", \"registered\":\"2017-04-29T10:16:00\" }"

The system cannot find the file specified.

왜냐하면, Windows Shell 명령어에서 <, > 문자는 Redirection 용도로 사용하기 때문입니다. 따라서 <, >와 같은 문자는 '^' 문자를 이용해 escape 처리를 해야 합니다.




참고로 openkoreantext-analyzer의 기본 설정은 "open-korean-text/elasticsearch-analysis-openkoreantext" 문서에 의하면 다음과 같다고 합니다.

"openkoreantext-analyzer": {
    "type": "custom",
    "tokenizer": "openkoreantext-tokenizer",
    "char_filter": [
        "openkoreantext-normalizer"
    ],
    "filter": [
        "openkoreantext-stemmer",
        "openkoreantext-redundant-filter",
        "classic",
        "length",
        "lowercase"
    ]
}

위의 구성에서 filter 부분의 순서가 의미가 있는데, 만약 lowercase를 다음과 같이 위로 설정해 놓으면,

"filter": [
    "lowercase"
    "openkoreantext-stemmer",
    "openkoreantext-redundant-filter",
]

다음과 같은 오류가 발생합니다.

{"error":{"root_cause":[{"type":"class_cast_exception","reason":"org.apache.lucene.analysis.LowerCaseFilter cannot be cast to org.apache.lucene.analysis.ko.KoreanTokenPrepareable"}],"type":"class_cast_exception","reason":"org.apache.lucene.analysis.LowerCaseFilter cannot be cast to org.apache.lucene.analysis.ko.KoreanTokenPrepareable"},"status":500}


만약 위와 같은 오류가 발생한다면 filter 항목의 순서를 조정할 필요가 있는 것입니다.




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







[최초 등록일: ]
[최종 수정일: 8/24/2018]

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

비밀번호

댓글 작성자
 




... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1554정성태12/26/201335303Windows: 78. 마음에 드는 윈도우 8.1 태블릿 - 델 베뉴 8 프로 5830 [4]
1553정성태12/26/201322342개발 환경 구성: 206. JNBridgePro와 한글 인코딩 문제파일 다운로드1
1552정성태12/25/201327525개발 환경 구성: 205. JNBridgePro를 이용해 C#에서 Java메서드 호출 테스트파일 다운로드1
1551정성태12/24/201322674.NET Framework: 398. tech-days 미니 토요세미나 - 3회 C#편 PPT 자료파일 다운로드1
1550정성태12/13/201325035Windows: 77. Windows 8 - 잠시 사용을 안하는 경우 화면 잠김 상태로 빠지는 문제
1549정성태12/13/201328639VC++: 73. IIS - ISAPI 필터 제작하는 방법 [2]
1548정성태12/10/201321308오류 유형: 198. C# - 제네릭 covariance/contravariance 사용할 때 컴파일 오류가 발생한다면?
1547정성태12/10/201330858.NET Framework: 397. C# - OCX 컨트롤에 구현된 메서드에 배열을 in, out으로 전달하는 방법파일 다운로드2
1546정성태11/28/201324741.NET Framework: 396. C# - 프로퍼티로 정의하면 필드보다 느릴까요? - windbg / ollydbg [3]
1545정성태11/28/201328642.NET Framework: 395. C# - 프로퍼티로 정의하면 필드보다 느릴까요? [3]
1544정성태11/27/201325123개발 환경 구성: 204. Visual Studio Online "Monaco" 서비스와 github 연동
1543정성태11/27/201329872오류 유형: 197. error MSB8008: Specified platform toolset (v120) is not installed or invalid. [1]
1542정성태11/27/201335440오류 유형: 196. The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll
1541정성태11/22/201336654.NET Framework: 394. async/await 사용 시 hang 문제가 발생하는 경우 [7]파일 다운로드1
1540정성태11/20/201325102개발 환경 구성: 203. Azure - WEB SITES 서비스 소개 [4]
1539정성태11/19/201329106VS.NET IDE: 83. 형상 관리 서버 운영을 대신해 주는 Visual Studio 온라인 서비스
1538정성태11/19/201329977오류 유형: 195. 웹 사이트의 모든 정적 컨텐츠 요청에 대해 "Internal Server Error" 응답
1537정성태11/19/201321613오류 유형: 194. 윈도우 서버 백업으로 인해 Hyper-V VM들의 상태가 모두 "Backing up..." 상태로 오래 지속되는 문제
1536정성태11/19/201326433오류 유형: 193. 윈도우 서버 백업 - Hyper-V 가상 머신이 백업되지 않는 경우
1535정성태11/18/201326546.NET Framework: 393. Internet Explorer 11에서 ASP.NET 컨트롤의 크기가 달라지는 문제 [1]
1534정성태11/13/201326526.NET Framework: 392. .NET 스레드 콜 스택 덤프 (6) - MDbg를 이용한 방법 [2]파일 다운로드1
1533정성태11/12/201333750기타: 39. Internet Explorer 11에서 유튜브 동영상의 1080p 옵션이 보이지 않는 경우 [5]
1532정성태11/5/201334656Phone: 8. 안드로이드용 Xamarin 개발 시 겪을 만한 시행 착오 정리 [6]
1531정성태11/5/201326063VS.NET IDE: 82. Visual Studio에서 Attach 메서드를 이용해 디버깅을 시작한 경우 Breakpoint가 안 잡힌다면?
1530정성태11/5/201327436기타: 38. 오픈소스로 풀린 하드 디스크 관리 도구 - WindowSMART
1529정성태11/5/201323326오류 유형: 192. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'.
... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...