쌓은 데이터를 잇고 쓸 때

한 번에, 데이터 있는 것부터

품앗이가 현장 데이터를 DB에 쌓은 뒤 그것을 갱신하고, 다른 자료와 잇고, 그 위에 구조를 세우다 넘어진 기록을 다른 조직이 다시 쓸 수 있게 옮긴 글입니다. 데이터를 꺼내고 옮기는 단계의 함정은 앞 글 현장 데이터를 꺼내고 옮길 때에 있습니다.

요지

데이터가 쌓인 다음의 실수는 대개 두 갈래였다고 우리 기록은 적고 있습니다. 하나는 한 줄씩, 또는 느슨한 규칙으로 처리해서 느리거나 틀리는 것입니다. 다른 하나는 데이터가 없는 개념부터 구조를 세우거나, 무겁다는 이유로 데이터를 뭉개서 구조가 살아 움직이지 않는 것입니다.

1. 원격 DB는 한 번에 처리한다

한 협동조합의 조합원 자료 20,573건을 원격 DB에 반영하면서 한 줄씩 조회하고 갱신했더니 10분이 넘도록 끝나지 않아 멈췄습니다. 같은 일을 임시 표에 한꺼번에 적재하고, 이어 붙여 갱신하고, 없는 것만 새로 넣는 방식으로 바꾸자 3초에 끝났습니다.

원격 DB는 질의 한 번마다 왕복 지연이 붙습니다. 기록에 따르면 질의당 약 0.1초였고, 2만 건을 조회와 갱신으로 두 번씩 부르면 4만 번이라 한 시간이 넘게 걸리는 계산이었습니다. 수백 건이 넘으면 처음부터 일괄 방식으로 짭니다. 만든 SQL을 화면에 찍지 말고 파일에 써서 실행합니다. 수천 줄짜리 SQL이 화면에 흐르면 AI가 한 번에 볼 수 있는 분량을 헛되이 씁니다.

2. 이름 매칭은 한 방향으로, 엄격하게

한 생협 매장의 상품 목록을 환경 인증 제품 DB와 맞춰 친환경 매출을 세려 했습니다. 상품명과 인증 제품명이 서로의 일부이기만 하면 짝을 지었더니 58건이 나왔고, 거의 다 틀린 짝이었습니다. 기록에 남은 예로 과일 「복숭아」가 음료 「복숭아 아이스티」에, 곡물 「현미」가 「현미 주방세제」에, 「플레인 요거트」가 「플레인」이라는 벽지에 붙었습니다.

그 기록에 남은, 고친 규칙은 넷입니다.

  1. 인증 대상인 공산품 분류에서만 매칭을 시도하고, 농산물과 식품은 처음부터 뺀다.
  2. 인증 제품명이 상품명 안에 들어 있을 때만 짝을 짓고, 반대 방향은 허용하지 않는다.
  3. 인증 제품명은 공백과 기호를 정리한 뒤 다섯 글자 이상일 때만 쓴다.
  4. 두 이름의 유사도 기준을 엄격하게 높게 잡아 애매한 짝은 버린다.

그래도 자동 매칭은 하한선일 뿐이라고 그 기록은 봅니다. 매장 자체 상표로 붙인 이름은 인증 DB와 맞을 수가 없습니다. 정답은 진열대에 붙은 인증 마크 실물입니다. 이름으로 잇는 일의 위험은 AX의 첫 세팅은 데이터베이스 구축 5단계에도 있습니다. 거기서는 이름으로 이은 거래처 매출이 실제의 두 배로 잡혔습니다.

3. 온톨로지는 데이터가 있는 것부터

조직의 개념과 관계를 정리하는 온톨로지를 시작하면서, 첫 작업으로 지역화폐 규칙을 적은 기록이 있습니다. DB에 지역화폐 데이터는 0건이었습니다. 개념이 깔끔해 보여서 골랐는데, 실제 데이터가 붙지 않는 구조는 죽은 구조입니다.

그래서 데이터가 풍부한 것부터 시작한다고 그 기록은 적습니다. 그 매장에는 상품 7,272개와 판매 거래 50만 건 넘게 쌓여 있었습니다. 데이터가 없는 개념은 데이터 작업을 먼저 하고 나중에 합류시킵니다. 같은 기록에 따르면 이 실수는 몇 주 전에 우리가 직접 쓴 입문 노드에 이미 그렇게 적혀 있었고, 그것을 검증 없이 따라 했던 것입니다. 우리가 만든 과거 산출물도 정본처럼 믿지 않습니다.

4. 디지털 트윈의 뼈대는 사건이다

한 생협의 디지털 트윈을 그래프로 처음 만들었을 때, 생산자와 상품에 속성은 잔뜩 달고 둘 사이의 관계는 빈약하게 두었습니다. 가장 큰 실수는 판매 거래를 노드로 만들지 않은 것이었습니다. 거래 64만 건이 무겁다며 생산자의 매출 합계라는 속성 하나로 뭉갰습니다. 그러자 노드 목록은 있는데 어느 노드에서 출발해도 다른 곳으로 건너갈 수 없는 그래프가 됐습니다.

그 기록에 따르면 생산자와 조합원, 상품과 매장을 잇는 중심은 판매라는 사건입니다. 거래, 주문, 방문 같은 사건을 독립 노드로 두고, 정방향 관계와 함께 역방향 관계도 둡니다. 「조합원은 조합에 속한다」와 함께 「조합에는 이 조합원들이 있다」를 두어야 어느 노드에서든 펼쳐 나갈 수 있습니다. 디지털 트윈이 무엇인지는 AX란 무엇인가에 있습니다.

「무거워서 집계로 대신한다」는 회피였습니다. 그 서버는 메모리 8GB에 챗봇과 여러 사이트가 함께 떠 있었는데도, 디스크 기반 그래프 DB는 2GB 힙으로 535만 개의 사실 단위(트리플)를 적재했고, 그 기록에 남은 방법은 이렇습니다.

  • 원천 DB에서 한 행씩 흘려 읽어 파이썬 메모리가 늘지 않게 한다.
  • 출력을 거래 5만 건 단위의 파일로 나눈다.
  • 한 파일씩 차례로 적재하고, 매번 남은 메모리를 확인해 기준보다 적으면 멈춘다.
  • 그래프 DB의 힙 상한을 정해 두어 다른 서비스를 밀어내지 않게 한다.

13번에 나눠 적재하는 동안 함께 돌던 챗봇은 멈추지 않았습니다.

5. 자기 데이터를 먼저 컴파일한다

한 생협 매장은 바깥 지식을 AI에게 넣는 데 한 주를 쓴 뒤, 이미 DB에 있던 판매 거래 53만 건으로 방향을 바꿨습니다. 거래와 출자, 포인트 기록으로 조합원마다 프로필을, 농가마다 단골 정보를 AI가 정리해 두자 단골 연결, 발주 추천, 이탈 감지 같은 질문에 답할 수 있게 됐습니다.

그 기록은 계층을 나눠서 봅니다. 원본 DB는 쓰고 고치는 자리, AI가 정리한 프로필 저장소는 읽기만 하는 자리입니다. 쓰기는 늘 원본에 하고, 정리본은 원본에서 다시 만듭니다.

6. 공공 API와 공유 DB 메모

법제처 공개 API에서 법령 전문을 받을 때는 검색 응답의 「법령일련번호」가 상세 조회에 넣는 법령 번호입니다. 공포됐지만 아직 시행 전인 법은 API에 없을 수 있습니다. 기록에 남은 한 신법은 검색 결과가 0건이었습니다. 법령 이름으로 검색하면 비슷한 이름이 섞입니다. 「전기사업법」을 찾으면 「전기공사업법」도 나오니, 이름이 정확히 같고 현행인 것만 받습니다. 법 원문을 AI에게 읽히는 방법은 법제처 API로 AI에게 법 원문을 읽히기에 있습니다.

한전 분산전원 연계 정보 API는 공공데이터포털이 아니라 한전의 전력데이터 개방 포털에서 따로 가입하고 따로 키를 받습니다. 공공데이터포털의 목록은 그 포털로 넘어가는 링크일 뿐이었습니다. 포털 화면의 메뉴 흐름을 짐작으로 안내했다가 두 번 틀린 기록이 있습니다. 화면의 메뉴 링크를 뽑아 확인한 뒤 안내합니다. 발급된 키를 캡처 화면에서 눈으로 옮겨 적으면 영문 O와 숫자 0이 헷갈리니, 그 값으로 바로 API를 불러 인증이 통과하는지로 확인합니다.

클라우드 DB 서비스의 무료 한도는 조직이 아니라 사람 단위로 붙을 수 있습니다. 우리가 쓰던 서비스는 본인이 소유자나 관리자인 조직의 프로젝트를 모두 합산했습니다. 한 교육기관의 멈춘 프로젝트를 깨우려고 우리 역할을 소유자로 올렸더니, 그 프로젝트들이 우리 한도에 잡혀 한도를 넘었고 그 조직 전체의 재개가 거부됐습니다. 역할을 되돌리고 그 조직의 소유자가 재개를 눌러 풀었습니다. 소유와 과금은 현장 조직이 쥐고 우리는 데이터 작업을 맡는 배치가 결과적으로 맞았습니다. 같은 기록에 따르면 이름만 보고 본체라 여긴 프로젝트가 열어 보니 연습용이었습니다. 프로젝트 이름은 내용의 증거가 아니니 표 목록을 봅니다.

공유 DB에 행 단위 정책을 새로 넣으면 기존 사용자가 조용히 막힐 수 있습니다. 한 공유 DB에 조직 번호로 행을 거르는 읽기 정책을 여러 표에 더했습니다. 기존 허용 정책이 있던 표는 무사했는데, 허용 정책이 없던 표에서는 새 정책이 유일한 문이 되었습니다. 데이터 행에는 조직 번호를 채웠지만 기존 직원 계정에는 그 번호가 없어서, 한 매장 직원 화면의 농가 검색이 0건이 됐습니다. 데이터 행을 채우는 일과 계정 정보를 채우는 일은 한 쌍으로 하고, 정책을 넣은 뒤에는 다른 서비스의 화면으로 실제로 회귀 시험을 합니다. 행 단위 보안을 켤 때의 다른 함정은 DB 권한과 격리의 실체에 있습니다.

처방 정리

  • 원격 DB 갱신은 임시 표에 한꺼번에 넣고 이어 붙여 처리한다.
  • 이름 매칭은 대상 분류를 좁히고, 한 방향으로, 최소 길이와 엄격한 기준을 둔다.
  • 온톨로지와 트윈은 데이터가 있는 것부터, 사건을 노드로 세운다. 무겁다고 뭉개지 말고 나눠서 적재한다.
  • 원본과 AI가 정리한 지식은 계층을 나눈다.
  • 공공 API는 화면 흐름을 짐작하지 말고 확인한 뒤 안내하고, 키는 실제 호출로 검증한다.
  • 남의 조직 DB에서 우리 역할을 올리기 전에 한도와 소유 구조를 본다.

도구 메모

  • 일괄 갱신: 임시 표를 만들고 파일을 통째로 적재한 뒤, 대상 표와 이어 붙여 갱신하고 없는 것만 새로 넣는다. 파이썬에서는 값 목록을 묶어 한 번의 갱신 질의로 보낸다.
  • 큰 그래프 적재: 원천 DB에서 이름 붙은 서버 쪽 커서로 흘려 읽고, 적재 사이마다 남은 메모리를 확인한다.
  • 정책 점검: 정책을 넣기 전에 DB의 정책 목록 표에서 대상 표에 기존 허용 정책이 있는지 조회한다.

관련 노드