2018. 9. 22. 00:43ㆍSearch-Engine/Elasticsearch&Solr
Solr 7.4.x version의 Tagger Handler를 이용한 NER(Named-Entity Recognition)
NER이란 자연어에서 뜻이 있는 단어를 뽑아내는 것이다. 챗봇처럼 자연어와 관련있는 기술에서 사용되는 기능인데, 예를 들어 "피자 주문할게요" 라는 질문이 있다. 이 문장에서 유추해 볼 수 있는 것은 "피자 주문" 이것을 더 보편화시켜 보면 "메뉴 주문"이라는 사용자질의 "의도"를 알 수 있다. 만약 "햄버거 주문할게요"라는 질의가 있으면 이 또한 "메뉴 주문"이라는 의도라는 것을 유추할 수 있다. 그럼 사용자가 어떠한 메뉴를 주문한다는 것은 알겠는데 그럼 그 메뉴가 무엇인가? 이러한 것이 챗봇에서는 NER이라는 기술로 추출해 낼 수 있는 단어라는 것이다. "피자 주문할게요"라는 질의의 의도는 "메뉴 주문" 개체명(Named-Entity)는 "피자"가 되는 것이다. 이렇게 의미있는 단어를 뽑아내는 것은 아주 중요한 챗봇의 기술이며 앞으로 더욱 발전해야할 기술이기도 하다. 이 NER 기술을 solr 7.4의 Tagger Handler를 이용하여 구현해 볼 것이다.
모든 구현은 Mac OS 환경에서 구현하였습니다.
우선 구현에 앞서 선행되어야 하는 것이, 바로 이전의 글인 Solr와 Zookeeper 연동입니다. 모든 환경은 solr cloud 환경에서 구현하였기에 중복되는 설명은 배제하였습니다.
$SOLR_HOME/server/solr 폴더 밑에 configset이 존재할 것입니다. 그 폴더를 보면 디폴트 환경설정 파일이 있는데, 그 안의 schema.xml과 solrconfig.xml 파일을 만질 것입니다. 이전에 따로 사용중이셨던 설정파일을 이용하셔도 무관합니다.
<schema.xml>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <field name="DOCID" type="string" indexed="true" stored="true" required="true" multiValued="false" /> <field name="NER_VALUE" type="text_general" indexed="true"/> <field name="NER_KEY" type="string" indexed="true"/> <field name="NER_TAG" type="tag" stored="false"/> <copyField source="NER_VALUE" dest="NER_TAG"/> <uniqueKey>DOCID</uniqueKey> <fieldtype name="tag" class="solr.TextField" positionIncrementGap="100" postingsFormat="FST50" omitTermFreqAndPositions="true" omitNorms="true"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.ConcatenateGraphFilterFactory" preservePositionIncrements="false"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.ASCIIFoldingFilterFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldtype> | cs |
적당한 위치에 선언해줍니다. NER과 관련된 필드들과 필드 타입을 선언한 설정입니다.
<solrconfig.xml>
1 2 3 4 5 | <requestHandler name="/tag" class="solr.TaggerRequestHandler"> <lst name="defaults"> <str name="field">NER_TAG</str> </lst> </requestHandler> | cs |
적당한 위치에 선언해줍니다. 개체명을 추출하기 위한 Tagger Handler를 등록하는 설정입니다.
만약 디폴트 설정파일을 이용하지 않고 새로 정의하셨다면 해당 설정 폴더를 SolrConifg/conf/ 밑으로 넣어줍니다.(SolrConfg는 맘대로정의 가능하지만 conf는 맞춰주셔야합니다.)
solr 디렉토리의 적당한 곳에 위치시켜줍니다. 그리고 난 후에 zookeeper에 upconfig를 합니다.(solr collection들이 사용할 설정파일을 zookeeper에 업로드하여 중앙에서 관리해줍니다.)
저는 앞으로 자주 사용할 가능성이 있다 판단이 되어서 쉘스크립트 실행파일을 만들어서 upconfig 했습니다.
<uploadSolrConfig.sh>
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash # usage uploadSolrConfig.sh zipConfigPath configName zkServers CONFIG_PATH=$1 CONFIG_NAME=$2 ZK_SERVERS=$3 # upload config info $HOME/solr/bin/solr zk upconfig -n $CONFIG_NAME -d $CONFIG_PATH -z $ZK_SERVERS echo $? | cs |
~$ ./uploadSolrConfig $SOLR_HOME/SolrConfig TaggerHandlerConf localhost:2181,localhost:2182,localhost:2183 으로 실행시켜줍니다.
이후 solr admin 페이지를 들어가서 cloud>file>confg에 생성한 이름으로 conf file이 생성되었는지 확인합니다. 그리고 Collection탭에 들어가서 생성한 conf file을 이용하여 컬렉션을 생성해줍니다.(collectionName = TaggerHandler)
<indexing file>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <add> <doc> <field name="DOCID">NER1</field> <field name="NER_VALUE">햄버거</field> <field name="NER_KEY">메뉴</field> </doc> <doc> <field name="DOCID">NER2</field> <field name="NER_VALUE">피자</field> <field name="NER_KEY">메뉴</field> </doc> <doc> <field name="DOCID">NER3</field> <field name="NER_VALUE">치킨</field> <field name="NER_KEY">메뉴</field> </doc> <doc> <field name="DOCID">NER</field> <field name="NER_VALUE">파스타</field> <field name="NER_KEY">메뉴</field> </doc> </add> | cs |
그리고 색인할 파일을 만듭니다.
$SOLR_HOME/bin/post -c TaggerHandler $SOLR_HOME/menu.xml 로 색인해줍니다.
이제 모든 작업이 끝이 났고, 적당한 request를 보내서 결과를 확인하면 됩니다.
요청은 POST 방식이고, 요청헤더에 Content-Type text/plain 요청바디에 "햄버거, 피자,피자 주문할게요"라는 질의를 넣고 밑의 요청을 보내면 (url 테스트를 위하여 저는 간편한 postman이라는 툴을 사용하였습니다. curl을 사용해도 무관합니다.)
http://localhost:8983/solr/TaggerHandler/tag?overlaps=NO_SUB&tagsLimit=5000&fl=DOCID,NER_VALUE,NER_KEY&wt=json&intent=on
{ "responseHeader": { "status": 0, "QTime": 35 }, "tagsCount": 3, "tags": [ [ "startOffset", 0, "endOffset", 3, "ids", [ "NER1" ] ], [ "startOffset", 5, "endOffset", 7, "ids", [ "NER2" ] ], [ "startOffset", 8, "endOffset", 10, "ids", [ "NER2" ] ] ], "response": { "numFound": 2, "start": 0, "docs": [ { "DOCID": "NER1", "NER_VALUE": "햄버거", "NER_KEY": "메뉴" }, { "DOCID": "NER2", "NER_VALUE": "피자", "NER_KEY": "메뉴" } ] } }
=>이런 결과가 나옵니다!!!
'Search-Engine > Elasticsearch&Solr' 카테고리의 다른 글
Elasticsearch - 3.부가적인 검색 API (0) | 2019.05.08 |
---|---|
Elasticsearch - 2.검색 API(Elasticsearch Query DSL) (0) | 2019.05.07 |
ELK - Filebeat 란? (실시간 로그 수집) (0) | 2019.03.20 |
Solr&Zookeeper(솔라&주키퍼) cloud 환경 구성 (1) | 2018.09.13 |
Elasticsearch 로컬(1개의 클러스터)에서 n개 이상 노드띄우기 (1) | 2018.07.07 |