티스토리 뷰

문제

이번에 블로그를 새로운 호스팅업체로 갈아타게 되면서 하나의 문제에 봉착했다. 바로 이전의 도메인이 달라졌다는 것. 그로 인하여 여태까지 내 블로그의 다른 글을 참조하거나 링크들은 다 이전의 도메인을 향하고 있을 것이라는 점이다.

import 기능의 활용?

처음에 이런 문제를 인식하고나서 봉착하게 되고 난 후 생각한 솔루션은 import를 2차로 진행하게 되면 어떨까 하는 것이었다. 예를 들어 워드프레스 관리자 화면 admin>tools>import 기능을 사용할 때 이미 해당 글이나 미디어가 존재하게 될 때 워드프레스는 두 가지로 대응할 것으로 예상되었다. 그때는 그것을 수정할 것인가 아니면 무시할 것인가. 만약 수정을 한다면 export 기능은 일괄 수정의 훌륭하고 안전한 방법이 될 것이라고 기대할 수 있다.

방법을 말하자면 처음에 export 받은 xml 파일 자체를 Notepad++와 같은 편집기로 열어서 일괄 수정한 뒤에 다시 import를 하는 것이다. 여기서 문제는 내가 이미 새로운 워드프레스 서비스에 import를 한 뒤라는 것이다. 그래서 문제가 복잡해진다. 따라서 다시 2차로 import를 하게 되면 어떻게 될까?

확인을 해보니 워드프레스는 import에서 이미 존재하는 글을 수정하지 않고 무시한다. 따라서 내 상황에서 import 기능 솔루션은 적절한 해답이 아니었다.

DB의 활용

따라서 생각할 수 있는 솔루션은 두 가지이다. 일괄수정용 플러그인을 사용하거나 MySQL에 접속해서 쿼리를 이용하여 일괄 수정하는 것이다. 나는 DB에 이미 익숙한 프로그래머이기 때문에 DB에서 직접 수정하였고 그 방법을 작성하고자 한다.

우선 여러 사람들은 여러 이유로 인해 여러 호스팅 업체를 사용할 것이다. 하지만 기본적으로 워드프레스를 제공하는 웹 호스팅 업체들은 MySQL 온라인 클라이언트를 제공하고 있는 것으로 안다.

나의 경우는 Bluehost인데 cPlanel의 phpMyAdmin 화면을 이용했다. Bluehost>Advances>데이터베이스>phpMyAdmin으로 들어가면 볼 수 있다. 여기서 SQL 탭을 클릭하여 쿼리문을 쓸 수 있는 화면으로 들어가자.

phpMyAdmin에서 데이터베이스에 들어간 화면

우선 글을 담고 있는 테이블이 어디있는지 확인해봐야 한다. 모든 워드프레스의 DB 테이블이 같은 구조일지는 모르겠다. 하지만 왠지 다를 수도 있다. 보통 {ID}__{테이블명}의 형식으로 테이블명이 정의되어 있는 것으로 보인다.

테이블 수가 비교적 적은 편이므로 찾기는 쉽다. 테이블명과 테이블의 글 내용이 들어간 컬럼명을 확인한 후 나는 다음의 쿼리를 이용하여 전체 스케일을 파악하는 것부터 출발했다. 우선 임의로 내가 바꾸고 싶은 텍스트를 "A_18'라고 하고 테이블명을 'ID_POST' 그리고 컬럼명을 'CONTENT'라고 하면.

SELECT count(*) FROM `ID_POST` WHERE POST_TYPE = 'POST' AND CONTENT like '%A_18%'

질의문 WHER 절에 LIKE '%%' 사이에 텍스트를 걸면 내용의 시작과 끝부터 'A_18'이라고 쓰여진 건 모두 나오게 된다. 그러면 SELECT 절의 COUNT를 통해 대체 글이 얼마나 있는 것인지 확인이 된다. 이 스케일을 잘 기억해두라.

2019.02.27 추가 코멘트:
오늘 확인한 건데 WHERE 절에 POST_TYPE = 'POST'라는 조건문을 앞에 꼭 넣어야 한다. 그렇지 않으면 포스트가 아닌 다른 시스템 데이터들까지 업데이트 되어 버리기 때문이다. 몰랐다;; 아마도 플러그인들이 이런 식으로 POST 테이블을 사용하나보다;;; 이 테이블엔 POST만 있을 줄 알았는데.. 이상하게 접근하네?? 아무튼 나 같은 경우 링크가 나온 건 24개 정도 나왔고 눈으로 글 데이터라는 걸 다 확인했었다. 이게 과거의 링크가 아니라 텍스트였으면 큰일 날 일... 이건 반드시 넣어야 한다.

다시 스케일을 확인했다면 다음의 쿼리를 실행하여 전체 내용을 확인해두라. 눈대중으로라도 말이다.

SELECT title ,content AS CONTENT ,REPLACE(content, 'A_18', 'A_18 ㅈ같애') AS MODIFY_CONTENT FROM `ID_POST` WHERE POST_TYPE = 'POST' AND content like '%A_18%'

이로부터 기존의 내용인 content 열과 수정된 뒤에 보일 modify_content를 직접 비교하여 눈으로 확인해볼 수 있게 된다. 혹시나 다른 의미로 쓰이는 것인데 잘못 수정되는 경우가 있는지 때문이다. 그런 케이스가 발견되면 다음의 where절에 조건을 추가하여 예외를 추가한다. 예외로 하고 싶은 데이터의 유일키인 id 값이 가장 좋긴 하지만, 여기서는 글 제목으로 추가. 수정하고 싶지 않은 글 제목이 예를 들어 '너를 사랑해'라고 한다면

SELECT title ,content AS CONTENT ,REPLACE(content, 'A_18', 'A_18 ㅈ같애') AS MODIFY_CONTENT FROM `ID_POST` WHERE POST_TYPE = 'POST' AND content like '%A_18%' and title != '너를 사랑해'

실행한 뒤에 다시 확인해보라. 여기서 "!="는 "<>"로도 쓸 수 있고 부정논리연산자이다. where절을 풀어서 설명하면 "content가 A_18이라는 텍스트를 포함한 경우이면서 title이 너를 사랑해가 아닌 모든 데이터"를 의미한다. 전체 스케일이 맞는지 확인해 둔 후 이제 이 쿼리를 이용하여 일괄 수정할 것이다. 다음으로 바꿔버려라.

UPDATE `ID_POST` SET content = REPLACE(content, 'A_18', 'A_18 ㅈ같애') WHERE POST_TYPE = 'POST' AND content like '%A_18%' and title != '너를 사랑해'

이제 해당하는 데이터에 대해 'A_18'이 'A_18 ㅈ같애'로 변경될 것이다. DB는 보통 변경이 일어난 Row Count 정보를 반환한다. 이로써 의도한 데이터 수를 변경한 것이 맞는지 검증해야한다. 하지만 오라클과 달리 MS-SQL처럼 MySQL은 Auto Commit인 것 같다.. 즉 수정하면 그대로 서버의 하드디스크 내용을 수정해버린다는 거다. DB 입장에서 업데이트 쿼리의 실행계획은 개발자가 Commit을 하기 전까지 캐시 형태로 메모리에 담아두기만 하고 해당 연결된 사용자의 세션에서만 보이도록만 하고 실제 디스크를 편집하지는 않는다. 이 데이터가 맞게 수정되지 않는 경우는 항상 존재하기 때문에 개발자는 보통 rollback을 시킬 방도를 고려해둔다. 이 경우는 Transaction 구문을 이옹하면 된다. 미리 알아둔 변경대상 카운트를 가지고 실제 변경된 수와 맞으면 Commit(하드디스크 변경)을 시키고 아니면 Rollback(취소)을 시키는 것이다. 그래서 나는 그렇게 하긴 했으나 여기서까지 그걸 설명하면 DB에 익숙하지 않은 분들에게는 어려운 부분이라 설명하지는 않겠다.

결론

나의 경우는 글 중에서 기존의 URL 정보만 새로운 URL로 수정하면 되기 때문에, 그리고 URL은 정말 URL의 의미로만 쓰였을 것이다. 이것이 다른 의미로써 쓰일 케이스는 매우 적다고 판단되었다.

하지만 좀 더 일반적인 의미에서 "개새"라는 말을 "십새"로 바꾸는 경우를 생각해보자. 컴퓨터는 개멍청해서 "거기 개새요?"와 같은 오타로 된 내용을 그대로~~~ "거기 십새요?"로 바꿔버릴 것이다;;;

이걸 바꿔 생각하면 오타가 아니라 의도적인 말장난의 경우는 노답이다. "4랑해 자氣"는 분명 '사랑해 자기"의 의미로 사람은 잘 인식하지만 컴퓨터는 멍청해서 '사랑해 자기'를 대응시키지 못한다. 이 문제는 실제 비즈니스에서도 많은 문제를 일으킨다. 개발자는 이 정보를 유일하게 대응시킬 컴퓨터만 알아듣는 key를 따로 만들기 때문에 데이터베이스의 정규화를 크게 걱정하지 않는다. (아니 실제로는 구조적 차원에서는 매우 신경쓴다고 해야겠다)

하지만 사람은 여러 경우를 대응시키기 때문에 이것만으로는 만족할 수 없는 고객의 요구사항이 생길 수 있다. 예를 들어 작업항목이라는 데이터에 "표본 채취"라는 항목이 있다고 하자. 사용자들은 이 정보가 안정적으로 하나만 존재하길 원한다. 그런데 "표본채취"나 "표 본 채취"나 이런 건 어떻게든 개발자가 case로 예외를 둬서 대응시키게 할 수는 잇지만 문제는 "샘플 채취" "샘플링" "샘플링 채취" "샘플 채굴" 뭐 이딴 식으로 쓰면 이건 개발자가 통제할 수 없을만큼 미치도록 확장된다;;;

그래서 이런 식의 요구사항은 비즈니스에서는 자주 있는 요구사항인데 보통은 불가합니다라고 해준다. 하지만 불가능하다고는 보진 않는데, 바로 "텍스트 마이닝"이 있기 때문이다. 사람도 '사랑해'와 '4랑해'를 대응시키는 이유는 그런 경험과 학습과정이 있기 때문인 것처럼, 텍스트 마이닝도 이를 대응시키는 것을 일종의 확률과정으로 받아들인다는 점에서 유사하다. 실제로 그 원조격이라 할 마르코프 자신도 자신의 확률과정모델을 가지고 세익스피어의 책을 분석했으니 이것이 후대의 텍스트 마이닝에 끼친 영향력은 상당할 것이다.

물론 텍스트 마이닝이 아니라도 개발자가 해줄 수 있는 텍스트 수정이야 넘치고 넘치긴 한다. 확률적인 문제는 좀 차원이 다른 문제다. 학부부터 이 문자열 처리를 존나게 배우기 때문에 왠만한 요구사항은 처리 가능하다. 예를 들어 "정규식"을 이용하면 정말 왠만한 예외는 처리 가능하다. 하지만 짜는 게 가장 힘들다;; 이번에는 도메인만 바꿀 수 있어서 다행이지만 잘못된 LaTeX 코드를 몇 건 발견해서 정규식을 써야 할 판인데.. 일단 이건 나중에 시간이 되면 처리하고 포스트를 하든 말든 하겠당.

[이관 글. 2019-02-25 작성]