2021년 10월 5일 화요일

엘라스틱 Runtime field - 3rd

다음은 url 필드에서 추출한 파일과 확장자 정보를 이용해서 런타임 필드를 만드는 painless 스크립트. 정보 추출 범위는 .을 포함한 url만으로 제한했다.
PUT iislog/_mapping
{
  "runtime": {
    "file": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = grok('.*\\/(?<file>.*)').extract(doc['url'].value).file;
          emit(result);
        }
      """
    },
    "ext": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = doc['url'].value.splitOnToken('.')[-1];
          emit(result);
        }
      """
    }
  }
}

잘 됨.


변수 길이도 측정해보자

param_len 필드를 추가하는 스크립트 추가. 숫자값을 저장할 필드이므로 keyword가 아닌 long 타입으로 지정. 정보 추출 범위는 값이 존재하는 필드만으로 제한했다.
PUT iislog/_mapping
{
  "runtime": {
    "file": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = grok('.*\\/(?<file>.*)').extract(doc['url'].value).file;
          emit(result);
        }
      """
    },
    "ext": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = doc['url'].value.splitOnToken('.')[-1];
          emit(result);
        }
      """
    },
    "param_len": {
      "type": "long",
      "script": """
        if (!doc['param'].empty) {
          String result = doc['param'].value.length();
          emit(result);
        }
      """
    }
  }
}

그런데 에러 발생.
{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "compile error",
        "script_stack" : [
          "... length();\n          emit(result);\n        }\n      ",
          "                             ^---- HERE"
        ],
        "script" : "\n        if (!doc['param'].empty) {\n          String result = doc['param'].value.length();\n          emit(result);\n        }\n      ",
        "lang" : "painless",
        "position" : {
          "offset" : 106,
          "start" : 81,
          "end" : 131
        }
      }
    ],
    "type" : "mapper_parsing_exception",
    "reason" : "Failed to parse mapping [_doc]: compile error",
    "caused_by" : {
      "type" : "script_exception",
      "reason" : "compile error",
      "script_stack" : [
        "... length();\n          emit(result);\n        }\n      ",
        "                             ^---- HERE"
      ],
      "script" : "\n        if (!doc['param'].empty) {\n          String result = doc['param'].value.length();\n          emit(result);\n        }\n      ",
      "lang" : "painless",
      "position" : {
        "offset" : 106,
        "start" : 81,
        "end" : 131
      },
      "caused_by" : {
        "type" : "class_cast_exception",
        "reason" : "Cannot cast from [java.lang.String] to [long]."
      }
    }
  },
  "status" : 400
}

마지막 에러 메시지를 보니 대충 string을 long 타입으로, 즉 문자형을 숫자형으로 바꿀 수 없다는 뜻인 듯. String 클래스(?)는 문자형 데이터 전용인가 보다. 

def 클래스는 만능
PUT iislog/_mapping
{
  "runtime": {
    "file": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = grok('.*\\/(?<file>.*)').extract(doc['url'].value).file;
          emit(result);
        }
      """
    },
    "ext": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          String result = doc['url'].value.splitOnToken('.')[-1];
          emit(result);
        }
      """
    },
    "param_len": {
      "type": "long",
      "script": """
        if (!doc['param'].empty) {
          def result = doc['param'].value.length();
          emit(result);
        }
      """
    }
  }
}

이제 잘 됨. 코딩 알못 살려주시는 구글신


문자, 숫자형 구분 귀찮으면 그냥 def 클래스만 사용해도 된다.
PUT iislog/_mapping
{
  "runtime": {
    "file": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          def result = grok('.*\\/(?<file>.*)').extract(doc['url'].value).file;
          emit(result);
        }
      """
    },
    "ext": {
      "type": "keyword",
      "script": """
        if (doc['url'].value.contains('.')) {
          def result = doc['url'].value.splitOnToken('.')[-1];
          emit(result);
        }
      """
    },
    "param_len": {
      "type": "long",
      "script": """
        if (!doc['param'].empty) {
          def result = doc['param'].value.length();
          emit(result);
        }
      """
    }
  }
}

댓글 없음:

댓글 쓰기

크리에이티브 커먼즈 라이선스