스터디 일정이 있어서 일찍 퇴근한 나는 내가 개발한 로그 페이지에 결과가 출력되지 않는다는 과장님의 카톡을 받게 된다.
다음날 아침 일찍부터 출근해서 문제를 파악해 보았다.
우리팀은 tts, stt, 대화엔진 등 여러 시스템을 거칠때마다 로그를 남긴다.
각 서비스간 연동 로그를 OpenSearch에서 조회해서 유의미한 정보로 가공한 후 스프링으로 백엔드 api를 구현하고 리액트로 프론트단까지 구현하는게 내 업무였다.
분명히 정말 동일한 코드로 생성된 동일한 쿼리가 날아가는데
왜 TB 환경에서는 되고 STG 환경에서는 되지 않는지 고민을 시작했다.
OpenSearch dashboard의 dev tools를 켜고 쿼리가 왜 안 되는지 조건을 하나씩 빼면서 실행해보았다
```
GET project_name_log_*/_search
{
"query": {
"bool" : {
"must" : [
{
"term" : {
"logType" : {
"value" : "SESSION",
"boost" : 1.0
}
}
},
{
"range" : {
"timestamp" : {
"from" : "20000101000000000",
"to" : "20250214235959000",
"include_lower" : true,
"include_upper" : true,
"boost" : 1.0
}
}
},
{
"term" : {
"baseInfo.tenantCode" : {
"value" : "TENANT1",
"boost" : 1.0
}
}
}
],
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
}
```
해당 쿼리를 STG에 날리면 결과가 0이고 TB에 날리면 결과가 1400개정도 나온다
그런데 여기서 다음과 같이 tenantCode 조건을 제거하면 STG에서도 결과가 0개가 아니게 된다
```
GET voicebot2_log_*/_search
{
"query": {
"bool" : {
"must" : [
{
"term" : {
"logType" : {
"value" : "SESSION",
"boost" : 1.0
}
}
},
{
"range" : {
"timestamp" : {
"from" : "20000101000000000",
"to" : "20250214235959000",
"include_lower" : true,
"include_upper" : true,
"boost" : 1.0
}
}
}
],
"adjust_pure_negative" : true,
"boost" : 1.0
}
}
}
```
테넌트 코드를 도대체 왜 못 읽을까 싶어서 이거저거 해보다가 매핑 구조도 찍어보았다
TB
```
"project_name_log_2025.02.12": {
"mappings": {
"baseInfo.tenantCode": {
"full_name": "baseInfo.tenantCode",
"mapping": {
"tenantCode": {
"type": "keyword"
}
}
}
}
}
```
STG
```
"project_name_log_2025.02.12": {
"mappings": {
"baseInfo.tenantCode": {
"full_name": "baseInfo.tenantCode",
"mapping": {
"tenantCode": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
```
원인
TB는 매핑이 keyword로 되어있었고
STG는 매핑이 text로 되어있는 문제가 있었다
STG 환경
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
- 메인 필드가 text 타입이면 텍스트 분석(analyze)이 일어나며, 토큰화되어 저장되게 된다
- keyword 서브필드는 원본 문자열을 그대로 저장하는 추가 필드이다
TB 환경
"type": "keyword"
- keyword 타입은 문자열을 있는 그대로 저장하고 분석 과정이 없다
서치하다가 다음 사실을 발견했다
- term 쿼리는 정확한 값 매칭을 수행하며 분석을 거치지 않음
- STG에서 baseInfo.tenantCode로 term 쿼리를 하면 text 타입 필드를 검색하게 되어 원하는 결과가 안 나옴
- TB에서는 keyword 타입이라 term 쿼리가 바로 정확한 매칭을 수행할 수 있음
그래서 STG 환경에서는 baseInfo.tenantCode.keyword로 검색해야 TB와 동일한 결과를 얻을 수 있었던 것!
나는 두군데 다 동일한 코드, term 쿼리로 날렸기 때문에 필드의 매핑 구조가 정확하게 일치해야만 검색이 되어서 결과값이 0이 되었던 것이다
해결책 1
내가 코드로 생성하는 term 쿼리에 .keyword를 추가하여 수정한다
```
{
"term": {
"baseInfo.tenantCode.keyword": "TENANT1"
}
}
```
그러나 더 나은 해결책을 위해 더 찾아보았다
해결책 2
```
STG에 날릴 때는 termQuery대신 matchQuery로 날린다
{
"match": {
"baseInfo.tenantCode": "TENANT1"
}
}
```
이렇게 하면 STG의 text 타입 필드에서도
TB의 keyword 타입 필드에서도 동일하게 작동하게 된다
해결책 3
STG의 타입 매핑을 keyword로 수정한다
해결책 2처럼 matchQuery를 날리면 키워드를 모두 분석해야 해서 성능에 안 좋다고 판단했다
해당 필드에 analyzer가 안 달려있을때는 termQuery와 matchQuery의 차이가 미미할 것 같기도 했지만
어차피 or 연산이나 유사한 검색까지 수행할 거 아니니까
가벼운 termQuery로 할 수 있게 필드를 바꾸는게 맞을 것 같았다
결국 로그 적재해주시는 분과 협의해서 필드의 매핑을 수정했다
재인덱싱을 해야 해서 오픈 후였다면 그냥 matchQuery를 썼을 것 같다