본문 바로가기
BE 공부/검색엔진

[ElasticSearch] 문자열 정렬

by 꼬질꼬질두부 2024. 8. 28.

ElasticSearch에서 employee 1부터 employee 20000까지 총 2만개의 데이터를 업데이트 했습니다.

그리고 id를

1. 'employee'라는 키워드로

2. id.keyword로 정렬하도록

3. 상위 5개만

{
        size: 3,
        query: {
            bool: {
                filter: {
                    term: {
                        name: 'jordan',
                    },
                },
            },
        },
        aggs: {
            employees_with_name_Jordan_per_company: {
                terms: {
                    field: 'company.keyword',
                },
            },
        },
        sort: [
            {
                'id.keyword': {
                    order: 'asc',
                    missing: '_last',
                },
            },
        ],
    };

 

이라는 조건으로 검색을 하니, 아래와 같은 결과가 나왔습니다.

 

last: ['employee 10000'],
list: [
    {
        _id: 'employee 1',
        _score: null,
        company: 'B',
        count: 1,
        department: 'HR',
        id: 'employee 1',
        name: 'Jordan Parker Reed',
        salary: 5000,
    },
    {
        _id: 'employee 10',
        _score: null,
        company: 'B',
        count: 0,
        department: 'Admin',
        id: 'employee 10',
        name: 'Casey Blake Cameron',
        salary: 16000,
    },
    {
        _id: 'employee 100',
        _score: null,
        company: 'B',
        count: 0,
        department: 'Admin',
        id: 'employee 100',
        name: 'Morgan Blake Bailey',
        salary: 16000,
    },
    {
        _id: 'employee 1000',
        _score: null,
        company: 'B',
        count: 0,
        department: 'Admin',
        id: 'employee 1000',
        name: 'Alex Blake Mason',
        salary: 16000,
    },
    {
        _id: 'employee 10000',
        _score: null,
        company: 'B',
        count: 0,
        department: 'Admin',
        id: 'employee 10000',
        name: 'Alex Blake Ellis',
        salary: 16000,
    },

 

이러한 결과에 대한 질문이 생겼습니다. (생겼다기보단 질문을 받았습니다..)

 

why [ employee 10000 ] in last?

저는 의식하지 못하고 있던 결과였는데, 질문을 받고 생각해보니 뭔가 조금 이상했습니다.

id로 sort했는데 왜 employee 12345가 나오지않고 1 10 100 1000 10000 가 나왔지?

 

조금 더 생각하니 답을 알 수 있었습니다.

 

문자열로 sort한 후 5개의 docs를 불러왔기 때문입니다.
그 결과, 정렬된 값들 중 상위 5개인 'employee 1', 'employee 10', 'employee 100', 'employee 1000', 'employee 10000' 가 return 되었고, last: ['employee 10000'],가 되었습니다.

문자열 정렬 예시
[ '1', '6', '100', '52', '1000', '101' ] -- 문자열 정렬 -> [ '1', '100', '1000', '101', '52', '6']

 

만약 문자열 숫자를 실제 숫자처럼 정렬하고 싶다면natural sort order 사용 있습니다.

 

natural sort order 문자열에 포함된 숫자를 문자 그대로가 아닌 실제 숫자값으로 인식하여 정렬하는 방식입니다.

정규식을 사용하여 문자열 내의 숫자를 추출하고, 이를 기준으로 정렬합니다.

 

만약 Elastic Search에서 natural sort order를 쓰고싶다면?

 

아까 작성한 쿼리문에 _script를 아래와 같이 추가해주면 됩니다.

예시)


  "sort": [
    {
      "_script": {
        "type": "number",
        "script": {
          "lang": "painless",
          "source": "def pattern = /\\d+/; def m = pattern.matcher(doc['id.keyword'].value); if (m.find()) { return Integer.parseInt(m.group(0)); } else { return 0; }"
        },
        "order": "asc"
      }
    },
    {
      "id.keyword": {
        "order": "asc",
        "missing": "_last"
      }
    }
  ]

 

당연히 엄청나게 많은 데이터들을 저렇게 정규화해서 쿼리하면 시간이 엄청 오래 걸리겠죠?

 

그러니깐 문자열을 실제 숫자처럼 정렬하고싶다면,

초기에 문자열 속 숫자 부분을 정수나 실수로 바꿔 애초에 저장해버리는게 더 좋을 것 같습니다~~

댓글