엘라스틱 서치 데이터 CRUD관련한 내용을 실습해보려고 한다.
Mysql처럼 샘플 대량의 데이터들을 한번에 import 할 수 있는게 없나 찾아봤다.
https://www.elastic.co/guide/kr/kibana/current/tutorial-load-dataset.html
역시 없을리가 없다!!!
튜토리얼을 보고 일단 그대로 따라해보자.
centos에서 주소를 치고 다운로드 받는다. 항상 느끼는 것이지만.. 빨리 컴퓨터를 바꿔야겠다. 정말 혈압이 오른다!
페이지에 나온 그대로, 다운로드 후 압축 해제 해준다.
이후, 셰익스 피어 데이터 집합에 대해 속성 매핑을 해줘야 한다. RDBMS로 생각하면, CREATE TABLE 이다!
근데 오류가 발생했다. 생각해보니 마스터 노드를 이름을 안바꿔 줬다.
다시 yml파일을 수정해보자.
여기서 cluster.initial_master_nodes 를 수정해주면 된다.
다시 curl 메세지를 보내보면 ..
똑같은 오류..? 앗 실수 ... yml파일을 수정하고 나면, 서비스를 재시작 해줘야 한다.
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch.service
sudo systemctl start elasticsearch.service
다시 curl 메세지를 보내보면 ..
또 똑같은 오류 ㅡㅡ ;
찾아보니, 마스터 노드 설정 옵션을 yml파일에 넣어줘야 한대서 생각해보니 안넣어줬었다. (설명은 다 써놓고 안넣음;;)
그래서 넣어줬다.
재시작 하고, 다시 curl보내는데 왜 안되는거냐?
왜 안되는 것인가..? 의문이다...
암튼 내가 뭔가 잘못 설정했기 때문에 안되는 것이겠지..
잘못한게 맞았다..
이유는 yml파일에 옵션을 넣을때의 형식은
옵션명: 값
이다. 여기서 주의할 점은 띄어쓰기 !!!!!
나중에 트러블슈팅을 한 내용은 따로 정리해둬야 겠다. 아무튼 ..
다시 재시작을 했는데, 안된다 ^^ 이번에는 포트 문제인 것 같았다.
그래서 열어놓은 포트를 확인해봤다.
열린 포트가 아무것도 없었다 !!!
9200, 9300 포트를 열어줬다.
사실 9300은 내부에서 노드간 통신시에 사용되기 때문에 열어줄 필요는 없다.
[irteamsu@localhost ~]$ firewall-cmd --zone=public --permanent --add-port=9300/tcp
success
[irteamsu@localhost ~]$ firewall-cmd --zone=public --permanent --add-port=9200/tcp
success
[irteamsu@localhost ~]$ firewall-cmd --reload
이렇게 해도 안되고 저렇게 해도 안돼서 분노를 참을 수 없어... 재설치 했다.
sudo yum remove elasticsearch
sudo yum install elasticsearch
이후, 다시 yml 파일을 설정해줬다.
cluster.name: my-application
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: localhost
http.port: 9200
transport.port: 9300
discovery.seed_hosts: localdamain
cluster.initial_master_nodes: ["node-1"]
바로 됐다. 왜그런거지..? 나중에서야 적는 내용이지만
일단 연결이 실패한 이유에는 크게 3가지로 무조건 수렴한다.
지금의 경우에는, 2번째 이유인 것 같다.
curl 명령어를 사용해 다시 타입 매핑을 해준다.
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/shakespeare -d '
{
"mappings" : {
"_default_" : {
"properties" : {
"speaker" : {"type": "string", "index" : "not_analyzed" },
"play_name" : {"type": "string", "index" : "not_analyzed" },
"line_id" : { "type" : "integer" },
"speech_number" : { "type" : "integer" }
}
}
}
}
';
하지만, 역시 쉽게 될리는 없었다.
이번에는 지원하지 않는 타입이라는 문구가 확인된다.
{"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"Root mapping definition has unsupported parameters: [_default_ : {properties={play_name={index=not_analyzed, type=string}, speech_number={type=integer}, speaker={index=not_analyzed, type=string}, line_id={type=integer}}}]"}],"type":"mapper_parsing_exception","reason":"Failed to parse mapping [_doc]: Root mapping definition has unsupported parameters: [_default_ : {properties={play_name={index=not_analyzed, type=string}, speech_number={type=integer}, speaker={index=not_analyzed, type=string}, line_id={type=integer}}}]","caused_by":{"type":"mapper_parsing_exception","reason":"Root mapping definition has unsupported parameters: [_default_ : {properties={play_name={index=not_analyzed, type=string}, speech_number={type=integer}, speaker={index=not_analyzed, type=string}, line_id={type=integer}}}]"}},"status":400}
일단 파싱 에러임으로, json 자체에 문제가 있나 확인해봤다. 디폴트 속성이 없어도 되는 것 같아서 제외하고 다시 curl을 날렸다.
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/shakespeare -d '
{
"mappings" : {
"properties" : {
"speaker" : {"type": "string", "index" : "not_analyzed" },
"play_name" : {"type": "string", "index" : "not_analyzed" },
"line_id" : { "type" : "integer" },
"speech_number" : { "type" : "integer" }
}
}
}
';
이번에는 이런 오류가 발생하여 찾아보니, text로 바꿔야 된다고 한다. 그리고, analyzed 옵션은 빼야 한다.
참조
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/shakespeare -d '
{
"mappings" : {
"properties" : {
"speaker" : {"type": "text"},
"play_name" : {"type": "text"},
"line_id" : { "type" : "integer" },
"speech_number" : { "type" : "integer" }
}
}
}
';
성공했다 !
{"acknowledged":true,"shards_acknowledged":true,"index":"shakespeare"}
다른 인덱스도 매핑시켜준다.
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/logstash-2015.05.18 -d '
{
"mappings": {
"properties": {
"geo": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
}
}
}
}
';
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/logstash-2015.05.19 -d '
{
"mappings": {
"properties": {
"geo": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
}
}
}
}
';
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/logstash-2015.05.20 -d '
{
"mappings": {
"properties": {
"geo": {
"properties": {
"coordinates": {
"type": "geo_point"
}
}
}
}
}
}
';
이제는 elasticsearch bulk API를 사용하여 다음 명령으로 데이터 집합을 로드한다.
curl -H 'Content-Type: application/x-ndjson' -XPOST 'localhost:9200/bank/account/_bulk?pretty' --data-binary @accounts.json
curl -H 'Content-Type: application/x-ndjson' -XPOST 'localhost:9200/shakespeare/_bulk?pretty' --data-binary @shakespeare.json
curl -H 'Content-Type: application/x-ndjson' -XPOST 'localhost:9200/_bulk?pretty' --data-binary @logs.jsonl
하다가 갑자기 Connection Refused 나와서 울 뻔했지만, 내 생각에 와이파이가 끊겼다가 재연결 되어서 그런듯 했다.
그래서 서비스를 재실행 해줬다.
sudo systemctl daemon-reload
sudo systemctl start elasticsearch.service
문제없이 실행됐다.
첫번째 명령어는 금방되는데, 두번째 명령어에서 오류가 발생했다.
{
"index" : {
"_index" : "shakespeare",
"_type" : "line",
"_id" : "111395",
"status" : 400,
"error" : {
"type" : "illegal_argument_exception",
"reason" : "mapper [speech_number] cannot be changed from type [integer] to [long]"
}
}
}
매핑을 다시 해줘야 했었다.
curl -H 'Content-Type: application/json' -XPUT http://localhost:9200/shakespeare -d '
{
"mappings" : {
"properties" : {
"speaker" : {"type": "text"},
"play_name" : {"type": "text"},
"line_id" : { "type" : "long" },
"speech_number" : { "type" : "long" }
}
}
}
';
https://www.elastic.co/guide/en/elasticsearch/reference/5.4/mapping.html
페이지를 참조해보면, 이미 매핑된 내용은 변경이 어렵다.
왜냐면, 이미 업데이트된 도큐먼트에 대해 무결성이 보장되기 어렵기 때문이다.
그래서 인덱스를 아예 삭제시켜줬다.
curl -s -XDELETE http://localhost:9200/shakespeare/
다시 long으로 변경된 매핑을 날리면, 성공했다는 문구가 확인된다.
이후 bulkAPI를 다시 사용한다.
https://www.elastic.co/kr/blog/index-type-parent-child-join-now-future-in-elasticsearch
흠.. 근데 오류가 생긴다.
이것은 엘라스틱 6.x에 발생했던 이슈인데, 나와는 관계가 없어보였다.
내가 매핑 정보를 잘못 입력했나 싶어 현재 버전대의 매핑 문서를 읽어봤다.
현재 7.9 버전대의 매핑 커맨드이다.
내것과 비교해서.. api 주소에 "mapping"이게 안붙었다.
다시 해봐야겠다.
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"age": { "type": "integer" },
"email": { "type": "keyword" },
"name": { "type": "text" }
}
}
}
'
위의 형식대로 수정하면 이렇게 된다. curl명령어의 순서만 달라졌다.
curl -X PUT "localhost:9200/shakespeare?pretty" -H 'Content-Type: application/json' -d'
{
"mappings" : {
"properties" : {
"speaker" : {"type": "text"},
"play_name" : {"type": "text"},
"line_id" : { "type" : "long" },
"speech_number" : { "type" : "long" }
}
}
}
';
성공 !!
(여기까지 오니까 생각해보니.. 샘플 데이터 로딩 관련된 문서는 그냥 처음부터 7.13 문서를 보면 되는데, 5.x대의 문서를 봐서 ;;;)
근데, 매핑오류가 다시 발생한다.
매핑 정보에도 오류가 없는데 왜..?
Rejecting mapping update to [shakespeare] as the final mapping would have more than 1 type [_doc,line]
오류메세지를 자세히 읽어보면, doc와 line이 같이 있으면 안된다는 의미같다.
doc와 line두가지에 연관성을 살펴봐야겠다.
데이터 자체가 예전 데이터라서 그런가 싶었다.
데이터를 확인해봤다.
{"index":
{"_index":"shakespeare",
"_type":"line", -> 요기 문제인것 같음
"_id":111393}
}
{"line_id":111394,
"play_name":"A Winters Tale",
"speech_number":38,
"line_number":"5.3.182",
"speaker":"LEONTES",
"text_entry":"Performd in this wide gap of time since first"
}
실제로 타입이 line으로 되어있어서 이부분이 잘못됐다 생각이 들었다.
인덱스 타입이 원래는 doc이어야 하는데 line으로 들어와서 문제라고 말하는 것 같았다.
5.4에서는 이게 왜 허용되었냐면, 이전 버전대에는 인덱스에 여러 타입이 들어와도 호환이 가능했지만 이로인한 이슈가 많아 엘라스틱 측에서 6.x버전 부터는 하나의 타입만 사용하도록 강제했다.
이렇게 타입이 1개밖에 없어서 7.x대 버전부터는 타입이 아예 사라졌다. 공식문서를 참고해보면, 샘플 데이터에 타입이 없는 것을 확인할 수 있다.
아놔; 처음부터 데이터 셋이 잘못되었던 것이다.
일단, 최근 버전대의 샘플 데이터 로드 방식을 살펴보니
키바나에서 따로 로딩해주는 설정이 있는 것 같았다.
일단 시행착오로 새겨두고, 키바나 설치 후 데이터를 로드해야겠다.
올려둔 인덱스 정보는 삭제한다.
일단 첫번째는 올라갔으니, 나머지 3개는 삭제했다.
curl -s -XDELETE http://localhost:9200/shakespeare/
curl -s -XDELETE http://localhost:9200/logstash-2015.05.18/
curl -s -XDELETE http://localhost:9200/logstash-2015.05.19/
curl -s -XDELETE http://localhost:9200/logstash-2015.05.20/