|
|
Boolean Model 소개
Boolean Model은 정보검색 분야에서 가장 오래된 모델중 하나이며, 거의 대부분의 상용/비상용 정보검색 시스템이 채택하고 있는 모델이다. 불리언이라는 용어가 의미하는 바와 같이, 이 모델은 집합이론에 근거한 불리언 로직을 이용해서 질의어와 문서를 색인어의 집합으로 표현하는 모델이다. 불리언 모델의 단점을 보완한 Extended Boolean Model 이 있는데, 이와 구분하기 위해서 Pure Boolean Model 이라고 부르기도 한다.
불리언 모델은 사용자 쿼리로 부터 주어진 Term을 포함한 문서를 찾는다고 하면, 해당 문서가 Term을 포함하고 있는지 (true), 아닌지 (false)에 대한 정보만을 가지고 문서를 찾아낸다. 매우 단순하고 효율적이며 빠른 구현이 가능하지만, 문헌의 우선순위나 사용자 질의에 대한 가중치등을 부여할 수 없기 때문에, 사용자의 의도와 다른 결과물을 보여줄 확률이 매우 높다.
때문에 검색엔진을 구현하기 위한 모델로는 거의 사용되지 않고 있다. 대부분의 검색엔진은 Extend Boolean Model이나 Vector Space Model을 쓴다.
하지만 사용자 질의 처리를 위한 목적으로는 여전히 널리 사용되고 있다. SQL혹은 검색엔진에서의 사용자 입력등에 있어서 불리언 모델은 가장 쉽고 일반적으로 사용할 수 있다. 이 문서에서는 사용자 질의 처리의 관점에서 불리언 모델이 가지는 장점과 구현 방법에 대해서 알아보려고 한다.
Boolean Query
불리언 모델은 매우 직관적이다. 검색질의어의 처리를 위해서 불리언 모델을 사용할 경우 해당 단어를 포함한다, 포함하지 않는다의
TRUE, FALSE로 단순화 시킬 수 있기 때문이다. 사용자 질의어를 처리하기 위해서 Boolean Model을 적용한 경우
Boolean Query라고 부른다. 물론 사용자 자연어에 좀더 가까운 사용자 질의어의 처리를 위해서 vector space
model이나 확장 불리언 모델을 사용할 수도 있을 것이다. 실제 이러한 시도도 이루어 지고는 있지만, 지나치게 복잡하고,
들이는 비용에 비해서 얻을 수 있는 이득이 별로 없기 때문에 그리 대중화되지는 못하고 있는 실정이다.
이를테면 다음과 같은 질의어의 작성이 가능하다.
- "A"와 "B"를 모두 포함하는 문서의 검색
+A +B
- "A"를 포함하지만 "B"를 포함하지 않는 문서의 검색
+A -B
몇몇 대중적인 검색서비스에서 '자연어를 입력하고 이를 처리'할수 있음을 마케팅 포인트로 부각시킨 적도 있었지만, 결국 형태소
분석을 동원한 Boolean Query의 응용일 따름이였다. 예컨데, "세상에서 가장 좋은 검색엔진시스템" 이라고 사용자가
쿼리를 입력하였을 경우 아래와 같이 단순 Boolean Query로 변경해서 사용한다. 순전히 형태소분석기의 영역이라고 볼 수
있을 것이다.
+세상 +가장 +좋은 +검색엔진시스템
Boolean Query의 확장
Boolean Query는 단순하다는 장점을 가지지만, 너무 단순해서 사용자의 의도를 충분히 파악하기 힘들다는 점이 단점이 된다.
이 문제는 True, False 외에도 Level과 Priority를 줌으로써 어느 정도 해결할 수가 있다. 이 방식은 형태소 분석기와 밀접한 관계를 가진다.
예를 들어 사용자가 "정보검색엔진" 이라는 질의어를 만들었다고 가정을 해보자. 이 쿼리를 순전히 불리언 모델에 의해서만 표현한다면, "정보검색엔진"을 포함한 문서를 찾아라고 검색엔진에 알려줄 수 있을 것이다.
그러나 이 경우 하나의 단어를 완전히 포함한 TRUE 상태의 문서들만이 검색대상이 되므로, 검색되는 문서의 양이 극히 적게 될 것이다. 사실은 정보검색 이라든지 검색엔진과 같은 단어를 포함한 문서도 충분히 가치있는 문서가 있을 수 있는데, 모두 제외되어 버리는 것이다.
그렇다면, 형태소 분석기를 이용해서 사용자질의어를 다음과 같은 stack 구조로 세분화해서 넘겨줄 수 있을 것이다.
(정보검색엔진(정보검색(정보)(검색))(검색엔진(검색)(엔진)))
다음과 같은 간단한 스택구조로 표현할 수 있다.
정보검색엔진 Level 1 | +------+-------+ | | 정보검색 검색엔진 Level 2 | | +---+---+ +---+---+ | | | | 정보 검색 검색 엔진 Level 3
이렇게 사용자 질의어를 형태소단위로 분류하면 다음과 같은 장점을 얻을 수 있다.
- 더 많은 문서를 검색해 낼 수 있다. - precision과 recall 을 적절히 조절할 수 있다 -
"정보검색엔진"을 모두 포함한 문서가 가장 좋은 문서일 확률이 높긴 하지만, 찾아낸게 100만개 문서중 5개 정도 문서라면, 그만큼 많은 좋은 문서를 놓치게 될 것이다. Recall이 너무 작아서 문제가 되는 경우다.
이 경우 "정보검색"을 포함한 문서까지 범위를 확대하게 되면, Recall을 높일 수 있을 것이고, 더 많은 문서를 검색해낼 수 있을 것이다.
- Level 에 따라 질의어에 가중치를 줄 수가 있다.
"정보검색엔진"을 포함한 문서는 1점, "정보검색"을 포함한 문서는 0.8점, "정보"를 포함한 문서는 0.7 점 하는 식이다.
이것은 우리의 직관과도 잘 맞아떨어지는 점이 있다. 정보검색 을 포함한 문서보다는 정보검색엔진을 모두 포함한 문서가 더 좋은
문서일 확률이 높기 때문이다.
- 검색 튜닝 포인트로의 활용
검색엔진을 만드는데, 가장 큰 넘어야될 산은 "문서의 양이 너무 많다"는 점일 것이다. 문서의 양이 많으면, 당연히 성능이
떨어질 수 밖에 없다. 1000만건의 문서에서, "A"라는 단어를 포함한 문서를 가져오는데 걸리는 시간이 3초라면 문제가 될 수
밖에 없을 것이다.
사용자가 "검색 엔진" 이라는 질의어를 선택했다고 보자. 검색을 포함한 문서가 500만건 엔진을 포함한 문서가 300만건
이라면, 이들 문서를 가져오고, score 연산을 해서 높은 점수의 문서가 위로 올라오게 하는 것만 해도 상당한 시간이 소비될
것이다.
이것을 "(검색엔진(검색)(엔진))"의 형식으로 표현했다고 가정해보자. 검색엔진을 포함한 문서는 당연히 더 적을 수 밖에 없을
것이다. "검색엔진"을 포함한 문서가 2000건 정도가 나왔다면, 검색 페이지 10개를 네비게이션할 수 있는 양이되므로, 굳이
"검색" 과 "엔진"을 모두 검사할 필요가 없을 것이다. 게다가 개개의 단어로 검색한 것 보다, 오히려 더 좋은 검색결과를
보장받을 수 있을 것이다. 800만건의 문서를 뒤져야 되는걸 2000건만 뒤지면 되니, 검색시간역시 크게 단축시킬 수 있을
것이다.
구현
일단 형태소 분석기가 stack 형태로 표현된 단어들을 리턴한다고 가정을 해보자. 대부분의 형태소 분석기가 당연히 지원하고 있는 기능일 것이므로, 이렇게 가정한다고 해도 문제되진 않을 것이다.
이렇게 해서 넘어온 정보를 분석하는 프로그램은 비교적 간단하게 구현해낼 수 있을 것이다.
- (를 만나면 depth++ 한다.
- )를 만나면 depth-- 한다.
- (와 )사이에 있는 것은 Term 이다.
#include <stdio.h> #include <string.h> #include <vector> #include <string>
using namespace std;
struct Term { string Term; int depth; };
int main(int argc, char **argv) { char *msg; int depth = 0; int i = 0, idx=0; char buf[80] = {0x00,}; vector<Term> TermInfo; Term lTerm;
if (argc != 2) { printf("Usage : %s [query]\n", argv[0]); return 0; } msg = argv[1];
for (i = 0; i < strlen(msg); i++) { if (msg[i] == '(') { if (idx > 0) { lTerm.Term = buf; lTerm.depth = depth; TermInfo.push_back(lTerm); memset(buf, 0x00, sizeof(buf)); idx = 0; } depth++; } else if (msg[i] == ')') { if (idx > 0) { lTerm.Term = buf; lTerm.depth = depth; TermInfo.push_back(lTerm); memset(buf, 0x00, sizeof(buf)); idx = 0; } depth--; } else { buf[idx] = msg[i]; idx++; } } for (i = 0; i < TermInfo.size(); i++) { printf("%s : %d\n", TermInfo[i].Term.c_str(), TermInfo[i].depth); } }
테스트 결과
# ./stack "(정보검색(정보)(검색))" 정보검색 : 1 정보 : 2 검색 : 2
# ./stack "(정보검색(정보)(검색))(시스템)" 정보검색 : 1 정보 : 2 검색 : 2 시스템 : 1
:::

공개 검색엔진 Lucene은 다양한 현대적인 검색모델을 지원하고 있으며, 학습용도 혹은 상업적인 용도 모두에 사용할 수 있다. 여기에서는 루신이 사용하는 모델중 Density based model에 대해서 알아보도록 하겠다.
루신은 vector space model기반으로하는 검색엔진이며, Document Term Weight의 계산을 위해서 TF - IDF을 사용하고 있다. 상당히 좋은 모델이긴 하지만 몇 가지 문제를 가지고 있다. 예를 들어 아래와 같은 3개의 문장을 포함한 문서가 있다고 가정해 보자.
- A : 구글 검색엔진 ... 그래서 ... 이러한 특징을 ... ... ... ... .. 이다.
- B : 구글은 최근 ... ... 하는 과정에서 ... 검색엔진을 ... .. ... 했다.
- C : 오늘 ... 검색을 해봤더니 ... ... 구글에서 ... ... 엔진은 역시 벤츠.
검색어는 구글 검색 엔진 이라고 가정해보자. 3문서 모두다 "구글 검색 엔진"을 포함하고 있으며, TF도 모두 1이다. IDF도
동일하다고 할 수 있으므로, 다른 조건이 같다면 A, B, C 는 모두 동일한 문서유사도를 가지게 될 것이다. 그러나 여러분은
각 문서의 유사도가 다르다는 것을 알고 있다. 인간은 내용을 모두 읽어보지 않더라도 A > B > C 순으로 문서가
유사하다는 것을 알아낼 수 있다. 바로 Term의 발생밀도를 가지고 예측을 하는 것이다.
A 번 문서는 "구글 검색 엔진"이 모두 동일한 위치에서 높은 밀도로 발생했으며, C 번 문서는 각각 다른 장소에서 낮은 밀도로
발생하고 있다. 그렇다면 A 문서가 더 높은 값을 가지도록 계산요소를 포함시킬 수 있을 것이다. 이러한 아이디어에서 만들어진
모델이 Density based model 이다. 단어의 발생위치를 기준으로 계산하는 특성 때문에 Proximity model이라고 부르기도 한다.
일반적인 공식은 다음과 같으며 Density Distance N-Gram Model을 위한 공식이다.
X와 Xmax의 거리가 증가함에 따른 감소 그래프는 대략 다음과 같을 것이다. 그래프는 gnupolot를 이용해서 생성했다.
공식에서는 x와 x_max의 거리값만을 가지고 계산을 하고 있지만, Lucene에서는 쿼리내의 모든 Term의 위치에 따른 연산을 수행한다. Lucene의 이 방식을 사용하면 검색품질을 높은 수준으로 끌어올릴 수 있지만 너무 느리다라는 결정적인 단점을 가진다.
이 모델을 적용하려면 tokenizing된
문서를 얻어내고, 모든 Term에 대해서 Term의 위치정보를 가지고 있어야 한다. 그리고 사용자 쿼리에 포함된 Term의
갯수만큼 loop를 돌면서 값을 계산해 내야 한다. 사용자 쿼리어에 포함된 Term이 많을 수록, 그리고 Term이 문서에서
여러번 등장할 수록 급격하게 연산횟수가 늘어남을 예상할 수 있을 것이다.
시간이 별로 중요하지 않은 내부검색용이라면 모르지만 상용으로 사용하고자 할경우 이 모델을 그대로 적용시키기엔 무리가 따를
것이다. 그렇다고 Density Distance N-Gram Model의 오리지날 공식을 그대로 사용하면, 좀더 빠르겠지만
결과가 만족스럽지 못할 것이다.
결국 성능과 검색품질 모두를 어느정도 만족하는 변형된 모델을 사용해야 할것이다. 이 방법은 관심이 있다면 한번 고민해 보기 바란다. 이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서 확인하세요. :::

1 MapReduce 소개
MapReduce는 대량의 자원을 다루는 분산/병렬 시스템의 효율적인 지원을 위한 목적으로 Google에
서 만들어낸 프로그래밍 모델이다. 테라바이트 단위의 데이터를 처리해야 하는 Google의 입장에서 분산/병렬 시스템을 지원하기
위한 이러한 툴의 개발은 필연적인 요구사항이였을 것이다. 분산/병렬 시스템의 효과적인 지원을 위해서는 다음의 사항들이 만족되어야
한다.
- 병렬처리 : 하나의 거대한 데이터는 여러개의 분산된 시스템으로 보내어져서 병렬적으로 처리될 수 있어야 한다.
- fault-tolerance : 병렬시스템중 몇개에 문제가 생기더라도 전체 시스템에 영향을 주면 안된다. 자동으로 관리할 수 있어야 한다.
- 데이터분산 및 로드밸런싱
2 프로그래밍 모델
용어에서 알 수 있듯이 MapReduce 는 Map과 Reduce가 합쳐진 용어로, Map 함수와 Reduce 함수의 조합을 통해서 분산/병렬 시스템운용을 지원한다. MapReduce는 데이터를 {Key, Value} 의 쌍으로 만들고 이를 처리하는 프로세스를 가진다.
Map은 사용자 정의 자료구조이며, 입력데이터에서 Key/Value 쌍으로 이루어진 중간 데이터 형태의 데이터를 만들어낸다. MapReduce 라이브러리는 Value에 대해서 Key I를 함께 관리한다. 그리고 이 중간데이터는 Reduce 함수로 넘겨진다.
Reduce 함수역시 유저에 의해서 작성되며, Key I와 Key I에 대한 Value를 받아들이게 된다. 그리고 Key값을 이용해서 Value값을 합치게 된다.
3 MapReduce 테스트
그럼 MapReduce 를 테스트 프로그램의 예를 들어서 이해를 해보도록 하겠다.
만들고자 하는 프로그램은 여러개의 문서로부터 각각의 단어가 몇개씩 있는지를 검사하는 프로그램이다. 제대로 테스트 하기 위해서는 분산시스템 환경을 만들어야 겠지만, 상황이 여의치 않으므로 로컬시스템에서 IPC를 이용해서 리모트 분산 환경을 흉내내도록 하겠다.
분석해야 하는 여러개의 입력 문서를 fork(2)된 worker 프로세스가 읽어들여서 Map으로 만든다음, 그 결과를 중간파일(Intermediate Files)로 저장한다. 저장한 중간파일은 다시 Recude worker 프로세스가 읽어들여서 최종 결과파일을 생성한다.
이를 리모트환경에서 구현을 한다면 Map worker 프로세스가 생성한 중간파일은 로컬 파일시스템에 저장되고, 원격지에 설치되어
있는 Reduce worker 프로세스가 파일을 잃어 가는 형식이 될것이다. User 프로그램은 각각의 worker프로세스에
작업을 할당하고 관리하는 일을 하게 된다.
로컬시스템에서 위의 환경을 흉내내고자 한다면 Reduce worker 프로세스가 IPC를 이용해서 중간파일을 읽어 가도록 바꾸면 될것이다.
위의 구조는 MapReduce 시스템의 구조를 단적으로 보여준다. 다만 응용범위와 환경에 따라서 다양한 방식으로의 구성이 가능할
것이다. 여기에서는 몇개의 영문서에서 단어를 카운팅하는 카운팅엔진으로 구현응용에 대해서 알아보도록 하겠다.
단순하게 생각하면, 파일단위로 map worker에 처리를 넘기도록 하면 되겠지만 이는 제대로된 병렬/분산 환경이라고 보기는
힘들다. 어떤 파일은 1Mega이고 어떤 파일은 100Mega일 수 있기 때문이다. 그러므로 여러개의 파일을 하나의 파일처럼
인식을 하고, 이것을 일정한 크기로 쪼개어서 읽어들이도록 해야 한다. User Program은 파일의 목록과 크기를
관리한다음에, 각각의 map worker 프로세스에게, 어떤 조각을 처리할지를 알려주는 역할을 한다. 이를 위해서 User
Program은 파일의 목록과 크기 뿐만 아니라, 해당 Worker가 파일의 범위를 찾아갈 수 있도록 offset정보도 유지를
해야 한다.
- User Program은 효율적인 병렬/분산처리가 가능하도록 파일을 일정한 크기를 가지는 M 개의 조각으로 쪼갠다.
- User Program에는 Master이라는 특별한 프로세스가 존재한다. Master은 worker에게 M map과 R reduce를 할당하며, 각 worker의 상태를 관리한다.
- worker은 할당된 문서를 읽어들인다음 유저정의 Map 함수를 이용해서 key/value 형태로 데이터를 읽어들인다.
Map함수는 만들어진 key/value를 buffer 메모리에 저장한다. 이 경우 key는 파일명이 될 것이고, value는
{단어,count}가 될 것이다.
- buffer 메모리(혹은 파일)에 있는 key/value는 주기적으로 지역파일에 쓴다. 이 파일은 master에 의해서 관리되며, reduce worker에 할당이 된다.
- reduce worker이 master로 부터 신호를받았다면, map worker에 의해서 지역파일에 씌여진
buffer 데이터를 가져온다. master와 reduce worker와의 통신은 remote procedure call등을
이용할 수 있을 것이다. 중간파일을 전부 읽어들였다면, 동일 key값을 이용해서, value와 관련된 필요한 계산을 하면 된다.
하나의 reduce작업에 다양한 종류의 key들이 존재하기 때문에, sort가 된후 작업이 되어질 필요가 있다. 이러한 작업은
상당히 많은 메모리를 차지하게 되는데, 이럴경우 다른 프로그램에 소트를 맡기도록 한다.
- reduce worker에서 소트를 해서 유일한 key를 만들어 낼 수 있게 되는데, 이때 사용자 정의된 Reduce
함수를 이용해서, value에 대한 연산을 하면 된다. 연산후 결과는 output 파일로 씌여지게 된다 output 파일로
씌여지게 된다.
- 모든 작업이 완료되었다면, reduce worker은 프로그램 리턴값을 User Program에게 넘겨준다.
3.2 Master 데이터 구조체
master은 map 작업, recude 작업과 진행상태(휴면,진행중,완료)와 worker 기계에 대한 정보를 유지하고 있어야 한다.
또한 중간파일을 reduce worker에게 분배하기 위해서, 완전히 작업이 끝난 파일에 대해서 크기를 모두 유지하고 있어야 한다. 그래야지만 reduce worker에게 할당할 데이터의 크기를 결정할 수 있기 때문이다.
3.3 Fault Tolerance
이러한 MapReduce 시스템은 크게는 수백에서 수천의 기계를 이용해서 정보를 처리해야 하는 경우가 생기며, 때문에 Fault
Tolerance는 매우 중요한 사항이다. 발생할수 있는 Fault의 형태에 따라서 어떻게 대응해야 하는지에 대해서 알아보도록
하자.
3.3.1 Worker Failure
worker에 주기적으로 Ping를 보내서 응답을 확인해야 한다. 만약 일정시간동안 응답이 없다면 worker에 문세가 생긴 것으로 간주한다. 이 경우 다른 idle상태의 worker를 찾아서 대신 처리하도록 해야 한다.
3.3.2 Master Failure
Master의 문제 해결은 비교적 간단하다. 이전 Master이 진행했던 작업이 중간파일 형태로 남아있고 이를 이용해서 checkpointe를 알아낼수 있다. 고로 그냥 Master를 다시 실행시키기만 하면 된다.
3.3.3 Semantics in ther Presence of Failures
네트워크 대역폭은 지역 컴퓨팅 환경에 비해서 상대적으로 열악하다. 특히 데이터가 다수의 원격 컴퓨터에 분산되어 있다면, 이를
처리하기 위한 환경을 만드는 것도 매우 힘든 작업이 될 수 있다. 때문에 네트워크 상에 가상의 파일시스템을 만들어서, 마치 로컬
컴퓨팅 환경인것 처럼 만들어줄 필요가 있다.
Google의 경우 GFS(Google File System)을 만들어서 이 문제를 해결하고 있다. 공개진영 소스에는 GFS(Global File System)가 사용되어지고 있다. 이들 주제는 별도의 페이지를 만들어서 정리해 보고자 한다.
4 샘플 프로그램
MapReduce 프로그래밍 모델을 테스트 하기 위해서 문서로부터 단어를 추출해서 카운팅하고, Map Reduce 과정을 거쳐서 최종의 결과물을 만드는 프로그램을 만들어 보도록 하겠다.
이 예제는 MapReduce의 이론적인 측면을 구현하는데 촛점을 맞출 것이다. Worker 스케쥴, Fault Tolerance
등은 고려되지 않을 것이다. Map Reduce 과정을 거쳐서 생성되는 Output File는 용이한 검색을 지원하기 위한 색인 DB가 될 것이다.
다음은 우리가 만들 색인 프로그램의 MapReduce 다이어그램이다.
- 4개의 RFC문서가 주어진다.
- map worker에 분배하기 위해서 4개의 문서를 3개의 조각으로 바꾼다.
- 3개의 map worker을 실행시키고, 각각의 조각을 읽어와서 <DID, Term> 형식의 데이터를 생성한다.
이 작업은 병렬적으로 수행된다.
- reduce worker에서 <DID, Term> 데이터를 읽어와서 <Term, DID>로 Term Invert한다.
- Term Invert된 데이터를 Term.idx 파일에 저장한다.
이렇게 해서 3개의 <Term, DID> .idx 파일이 생성되었다고 가정을 해보자. 만들어진 결과물이, 색인데이터로써의 기능을 수행하기 위해서는 3개의 데이터를 다시 합쳐서 중복된 Term은 제거하고, 여러개의 문서에 포함되어 있는 Term은 하나의 레코드로 만들어줘야 한다. 아마도 아래와 같은 자료구조를 가질 것이다.
struct LastIndexResult { string Term; vector<string> DID; } set<LastIndexResult> IndexSet;
그 다음 위의 정보를 파일로 전부 쓰면 된다. 라고 간단히 설명은 했지만, 쉬운 방법으로 해결할 순 없다. 쉽게 생각해보자면
각각의 .idx파일에 이미 Term으로 정렬된 값이 들어가 있으므로, IndexSet을 만드는게 그리 문제되지 않을 거라 생각할
수 있지만, 문서의 양이 많아질 경우 "엄청난 양의 메모리를 소비"해야 한다는 문제가 생길 수 있기 때문이다. 그러므로 데이터를
전부 메모리에 넣어서 정렬하는 것보다는 정렬된 중간파일을 만들어서 병합시켜주는 과정이 필요하다. 귀찮기는 하지만 .idx의
값들은 모두 정렬되어 있으므로, 중간파일을 만들어서 병합시키고 OUTPUT 파일을 만드는건 어려운 작업은 아닐 것이다.
.idx +--------------------+ | A D I O Q R V X Z | ---+ +--------------------+ | +--------------------+ |-----+ | A B J K L V Z | ---+ | +--------------------+ |-----> OUTPUT set<LastIndexResult> +--------------------+ | | A B K L O P X Z | ---+ | +--------------------+ |-----+ +--------------------+ | | C I J Q R W Z | ---+ +--------------------+
색인에서 예제로 제시한 indexer를 수정하는 형태로 만들도록 하겠다.
5 Nutch의 MapReduce 엔진
MapReduce는 프로그래밍 모델이고, 실제 활용하기 위해서는 MapReduce프로그래밍 모델이 적용된 MapReduce 엔진이 필요하다. 이 엔진을 위해서는 크게 다음과 같은 3개의 요소가 필요할 것이다.
- Mapper
Map Task를 실행하기 위한 프로세스로, 파일을 Split 하고, Split된 각 부분을 읽어서 <Key,
Value>로 만들기 위한 function을 가진다. <Key, Value>의 목록은 중간파일 형태로 저장이 될
것이다.
- Reducer
Reduce Task를 실행하기 위한 프로세스로, Mapper에 의해서 중간파일 형태로 저장된 <Key, Value>파일을 읽어들여서, 결과파일로 만들어 낸다.
- Job Tracker
각 Task를 실행하는 Job을 제어하기 위한 프로세스. Mapper과 Reduce를 실행시키고 Job을 할당한다.
MapReduce엔진은 일종의 프레임워크라
고 볼 수 있으므로, 다양한 Job을 실행할 수 있어야 한다. 때로는 색인파일을 만들어야 하고, 때로는 네트워크 파일시스템을
만들 수 있어야 한다. 그렇다면 주어진일을 할 수 있는 Job을 배포할 수 있도록 시스템/소프트웨어적으로 구성이 되어야 할
것이다.
Java로 구현할 경우에는 바이트코드를 배포하면 되므로, 시스템이나 운영체제에 관계없이 비교적 쉽게 배포시스템을 만들 수 있을 것이다. Perl, Python등을 이용해서 구현해도 Java와 동일한 효과를 얻을 수 있을 것이다.
컴파일 언어- C/ C++
같은 -로 구현을 한다면, 시스템과 운영체제에 의존적이 될 것이다. 가장 좋은 방법은 모든 시스템을 동일한 운영체제와 동일한
컴파일러, 라이브러리를 가지도록 세팅 하는 것이다. 꽤나 주의 깊은 작업을 필요로 할 것이고, 독자적인 운영체제 배포판을 하나
만드는게 가장 좋을 것이다.
C/C++에서 job의 배포는 공유 라이브러리형태로 배포되어야 할 것이다. 무가동 시스템으로 만들려면 동적 라이브러리 형태로 만들어서, signal이 주어질 때, 다운로드 받은 라이브러리를 동적으로 적재시키는 방식을 사용해야 할 것이다.
6 참고문헌
-
mapreduce-osdi04.pdf
- http://jaso.co.kr/tatter/index.php?pl=133 C언어를 이용한 hadoop 파일 시스템 처리
- http://www.jaso.co.kr/tatter/index.php?page=8&setdate=200609 hadoop 살펴보기
- http://wiki.apache.org/lucene-hadoop/HadoopMapReduce Hadoop MapReduce
-
다카하시의 radium software 내의 MapReduce 번역 : 한글문서
-
쓰레드 베이스의 MapReduce : 한글문서
-
MapReduce 소개글 : 한글문서
이 문서는 수정될 수 있습니다. 최신 문서는 Joinc Wiki에서 확인해 주세요. :::

2007/6/20일 현재 개인적으로 운영하는 wiki 사이트인 Joinc에서 관리되는 페이지가 2219개로 나오고 있다. 이중 꽤많은 양이 페이지 리다이렉트만을 위한 것임을 감안하면, 대략 1900건 정도의 문서가 있을 거라고 생각이된다. 이 정도수의 문서라면 검색엔진최적화시도를 했을 경우 효과가 분명히 나타날 것이라고 생각해서 5월 1일 부터 최적화 작업을 수행하기 시작했다. 최적화를 위해 사용된 기법들은 다음과 같다.
- Blog를 통한 배포.
배포경로가 두개가 된다는 점외에도 커뮤니티 형성이 가능하다는 장점이 있다. 우리나라에서 wiki는 커뮤니티 형성이 거의 제로다. 위키에서의 커뮤니티라면 문서의 작성과 수정을 통해서 이루어지게 될건데, 실제 내 사이트에서 관리되는 문서의 95%이상은 내가 작성한 문서이며, 10페이지 이상 문서를 작성한 저자는 단 2명이다. 블로그는 이런점에서 훌륭한 커뮤니티 시스템이다. 커뮤니티로써의 블로그의 특징은 블로그 검색엔진의 미래 에 나름 생각을 정리해 둔게 있다.
- 문서 타이틀의 재작성
이와 관련된 얘기는 검색엔진 최적화에 정리해둔걸 읽어 보기 바란다. 주로 문서의 특성이 최대한 잘 들어나게끔 제목을 재작성하는데, 많은 노력을 들였다. 예를 들어 문서의 제목이 malloc 이였다면, linux man page : malloc - 커널에 메모리 할당을 요청 이런 식으로 변경했다. 문서의 양이 많아서 모두다 하지는 못하고, 중요도가 높다고 생각되는 문서의 제목을 우선 최적화 시켰다.
- 링크의 사용
포스트를 작성하고나면, 관련된 다른 블로거의 포스트를 찾아서 적극적으로 트랙백을 걸었다. 포스트와 관련된 다른 정보들을 얻을 수 있고, 커뮤니티를 형성할 수 있으며, 장기적으로 PageRank를 높이는 효과를 얻을 수 있다. 또한 블로그 포스트의 경우, 링크가 wiki의 원문으로 연결된 경우가 많은데, 역시 링크에 의한 페이지 중요도를 높일 수 있을 거라 생각했다.
아래는 최근 한달동안 검색엔진을 통한 방문을 일별로 분석해본 결과다. 아래의 결과는 google analytics를 이용해서 작성했다.
Analytics.pdf 구글 분석기 PDF 결과
5월 초에 최적화 작업을 시작했었는데, 중순이 넘어서부터 조금씩 효과가 나타나는걸 확인할 수 있다. 아마도 구글 검색엔진의
문서 crawling(수집)주기 때문인것으로 생각된다. 5월초 검색엔진을 통한 유입율은 110 정도였는데, 대략 한달후인
6월달은 거의 800정도가 7배나 증가했다. 문서의 10%도 최적화를 못했다고 생각되는데, 엄청난 증가율이라고 볼 수 있을
것같다.
물론 이러한 결과를 단지 검색엔진 최적화를 잘해서라고 보기는 힘들 것이다. 구글이 국내에 본격적으로 진출하면서, 구글 검색엔진
사용자 자체가 늘었다거나 하는 등의 요인이 있을 수 있기 때문이다. 하지만 이러한 것을 감안하더라도 (사실 그 짧은 시간에 구글
사용자가 얼마나 늘었겠는가) 상당한 증가율인 것만은 분명하다. 이 문서는 수정될 수 있습니다. 최신 문서는 Joinc Wiki에서 확인하실 수 있습니다. :::

어느 정도 컨텐츠가 확보되면, 사용자가 원할 것 같은 정보를 어떻게 효율적으로 보여줄 수 있을 것인가가 문제가 된다. 아무리 좋은 컨텐츠가 있어도 찾기 힘들거나 찾지를 못한다면 말짱 도루묵이란 얘기가 되겠다.
쉽게할 수 있는 시도는 카테고리, 태그 클라우드 등을 활용하는게 되겠지만 얘들은 고유의 한계를 가지고 있다. 카테고리는 컨텐츠의
양이 적을 경우에는 괜찮지만 많을 경우 카테고리간 병합, 카테고리 분리와 같은 복잡한 문제가 발생한다. 거기에 카테고리를
분류하기 애매모호하거나 여러 관련된 카테고리를 가지고 있을때 처리하기가 더욱 힘들어진다. 지나치게 카테고리가 많아지거나 원하는
정보를 찾기 위해서 어느카테고리를 방문해야 하는지 명확하지 않은 문제도 발생한다.
태그역시 마찬가지인데, 태그는 관심있는 Term을 나타내주는 도구일 뿐이다. 사이트 주인이 관심있어 하는 분야를 대략적으로 확인할 수는 있겠지만, 방문자가 원하는 정보를 찾을 수 있게 해주는 효율적인 도구는 아니다.
이 포스트는 이에 대한 해결책을 제시하기 위한 목적으로 만들어졌다. 이 포스트의 방법들을 응용하기 위해서는 약간의 프로그래밍 능력이 요구된다.
링크의 활용
가장 쉽게 생각할 수 있는 방법은 링크를 이용해서 문서와 문서를 연결하는 방법일 것이다. 이 방법은 효율적이긴 하지만 다음과 같은 단점이 있다.
- 관련된 링크페이지를 찾는 것은 매우 번거로운 작업이다.
- 일반적으로 하나의 링크는 하나의 페이지에 대응한다. 여러개의 페이지를 링크하는건 힘들거나 귀찮다.
어떻게 하면 링크를 장점을 유지하면서, 간단하고 효율적으로 사용할 수 있을까를 고민하다가 생각해낸게, 그렇다면 중간에 메타 정보를 가지는 페이지를 만들어 보자 였다. 이에 대한 개념은 Related Link 프로젝트문
서에 정리되어 있다. 이 개념은 필자가 운영하는 사이트들에 실제로 적용되어 있다. 링크 시키기 원하는 정보가 있다면 고민할 필요
없이 문자뒤에 괄호를 붙여주면, 알아서 Meta Page를 뒤져서 해당 정보로 연결시켜 준다. 링크가 존재하지 않는다면? 그럴땐
구글 검색엔진으로 보내거나 메타페이지 하나 생성시키면 그만이다.
현재 사용하는 메타페이지는 man 메타페이지를 방문해보기 바란다. 링크를 건 단어가 man 밑에 있다면 해당 페이지로 이동한다.
이를 위해서 약간의 정규식을 이용한 약간의 코딩을 했다.
if (ereg("\([:][0-9]+[,]", $line)) { $line2 = ereg_replace("([ \t\n]+)([^ <>=\.\(\)]+)\(([:][0-9]*),([^,]*)\)", "\\1<a href=\"$url_prefix/wiki.php/manSearch?google=none&name=\\2\">\\4</a>", $line); }
검색엔진의 활용
이렇게 메타페이지를 만들어서 링크를 활용할 수 있는 기반은 만들었지만, 모든 단어에 대한 링크를 위한 메타페이지를 만드는 데에는 많은 시간이 걸린다. 이건 오랜시간에 걸쳐서 서서히 완성해나가야할 작업이다. 하지만 그 시간동안 링크를 대체할 수단을 준비해야 한다. 그래서 생각해 낸게 단어에 대한 메타페이지가 없다면, 사이트내에서 검색을 하도록 하자 라는 아이디어였다.
과거에는 사이트내에 검색엔진을 만드는건 매우 힘든작업이다. 회사에서나 엄두를 낼 수 있는 작업이였으며, 많은 시간과 비용이 소모되었었다. 그러나 지금은 30분이면 개인 사이트에 검색엔진을 붙일 수 있게 되었다. 구글 맞춤검색을 이용하면 아주 간단하게, 그러나 매우 높은 검색품질을 보여주는 검색엔진을 붙일 수 있다. 지금 이 포스트에서도 몇몇 링크는 메타페이지로, 몇몇 페이지는 검색결과 페이지로 이동하는걸 확인할 수 있을 것이다. 태터툴즈사용자를 위한 검색엔진 붙이기 팁도 있으니 확인해 보기 바란다. :::

이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki 에서 확인하세요. 검색은 망망대해에 투망을 던져서 원하는 고기를 잡는 행위에 비유되곤 한다. 이때 우리는 투망범위를 조절함으로써, 잡을 수 있는
물고기의 종류와 양을 어느정도 결정할 수 있을 것이다. 투망범위를 넓게하면 많은 물고기를 건져올릴 수 있겠지만 많은 물고기를
건져올린다는게 항상 좋은건 아니다. 원하지 않는 쓸데없는 물고기들도 잔뜩 올라와서 골라내는 작업에 많은 시간을 소비할 수 있기 때문이다.
투망범위를 작게 하면, 원하는 물고기만 잡을 수 있겠지만 걸려든 물고기의 양이 너무적은 문제가 발생할 수 있다. -혹은 아예 걸려들지 않을 수도 있을 것이다- 그러므로 그물의 눈을 적당히 조절할 필요가 있다.
문서의 바다에서 원하는 검색어를 포함하는 문서를 찾아야 한다는 점에서 검색도 투망과 비슷하다고 볼 수 있다. 검색어와 관련된 문서를 많이 찾아내면, 문서의 양이 많아서 좋을 수도 있지만 필요없는 문서가 다수 포함될 수 있다. 반면 보수적인 알고리즘을 적용해서 적은양의 문서를 찾아내면, 문서의 양이 너무 적어져서 원하는 문서가 검색되지 않는 문제가 발생할 수 있다.
검색에서는 이를 recall 과 precision으로 나타낸다.
precision
가져온 문서중 실제관련있는 문서의 비율이다. - 그물에 걸린 물고기들 중 실제 잡기 원하는 물고기의 비율 -
파란점 : 관련있는 문서
빨간점 : 검색은 되었지만 관련은 없는 문서
다음과 같은 공식으로 나타낼 수 있다.
Recall
전체 문서셋에 있는 관련있는 문서셋 중에서 건져올린 문서의 비율이다. - 그물을 던진 범위 -
파란점 : 관련있는 문서
빨간색원 : 실제 찾아낸 문서
예
100개의 문서셋이 있고, 이중 리눅스와 관련있는 문서가 30개 였다고 가정해보자. 사용자가 쿼리어를 주었을 때, 검색엔진이 15개의 결과를 되돌려주고, 첫 페이지에 표시되는 상위 10개의 문서중 실제 리눅스와 관련된 문서가 8개였다면 precision과 recall은 아래와 같이 계산될 수 있다.
상위 10개에서의 precision = 8/10 = 0.8 recall = 15/30 = 0.5
precision 과 Recall 의 관계
일반적으로 이들은 서로 반비례관계에 있다.
- Recall을 높일 경우 : Recall을 높이면 많은 문서를 가져오게 된다. 여기에는 관련있는 문서도 포함되겠지만 그렇지 않은 문서도 포함이 된다. 결국 precision이 낮아지게 될 것이다.
- Recall이 낮을 경우 : 문서의 범위를 한정할 수 있으므로, precision이 높아지게 될 것이다. 그러나 범위가 한정되는 만큼, 많은 관련있는 문서를 놓치게 될 것이다.
검색서비스에 있어서 이들의 균형을 맞추는 것은 매우 중요하다. 또한 검색서비스의 종류에 따라 어느쪽을 중요시 할건지도 달라진다.
웹문서
검색의 대상을 웹문서로 하는 경우를 생각해보자. 웹에는 대량의 문서가 존재하며, 이 중 거의 대부분은 주어진 쿼리에 대해서 연관성이 없거나 아주 약한 연관성을 가지고 있다. 전체 문서셋중 아주 일부만이 봐줄만한 연관성을 가지고 있을 뿐이다. 그러므로 Recall을 낮추어서 precision을 높여줄 필요가 있다. 안그러면 엄청나게 많은 별로 유사하지 않는 문서들의 소용돌이에서 헤엄치게 될 것이다.
Recall을 낮췄음으로 놓치는 문서들이 생기게 될 것이다. 하지만 문서의 양이 워낙 많고, 많은 연관성 있는 문서들이 비슷비슷한 내용들을 가지고 있을 것이라고 판단할 수 있으므로, 어느정도 놓치는 것은 무시한다.
논문
논문은 문서의 양이 그렇게 많지 않다. 또한 연관성이 적어보이는 논문이라도 이용자에 따라서 매우 중요한 논문일 수 있다. 그러므로 Recall을 높이고 precision을 낮추는 방향으로 튜닝을 해야 할 것이다.
참고문헌
:::

이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서 확인하세요.
term vector model이라고도 불리우는 Vector space model은 정보필터링, 문서내에서의 정보검색, 색인과 유사도를 계산하기 위한 수학모델로, 다차원 선형공간에서의 Vector 정보를 이용해서 자연어를 포함한 문서의 중요도를 분석하기 위한 방법을 제시한다. 이 모델은 SMART Information Retrieval System에서 가장 먼저 언급되었다.
문서는 색인단어의 vector로 나타낼 수 있을 것이다. 문서의 유사도는 Vector에 위치한 단어들간의 거리로 계산해낼 수 있을 것이다 라는게 이 모델의 대전제다. vector에 위치한 쿼리에 대한 문서의 유사도는 다음과 같은 간단한 삼각 공식으로 나타낼 수 있다.
TF - IDF 모델
Vector Space Model을 사용하기 위해서는 문서의 Vector 공간에 있는 Term의 가중치(weights)를 계산하고 있어야 한다. 이를 위해서 term frequency - inverse document frequency 모델이 사용되고 있다.
- TF : 문서 Vector에 존재하는 Term의 갯수
- IDF : Term을 Vector에 포함하고 있는 모든 문서들
- Weight = TF * IDF
문서 d가 있다면, Vector d는
에서
IDF에서 |D|는 문서의 총갯수이고  는 Term을 포함한 문서의 갯수다.
예를 들자면 리눅스(:12)라는 쿼리어가 주어졌을 때 유사한 문서는 리눅스를 많이 포함한 문서일 거라고 예상할 수 있다. 이것이 TF다.
일반적인 단어는 여러문서에 걸쳐서 나올 것이고, 이러한 단어를 포함한 문서는 낮은 유사성을 가질 것이라고 예상할 수 있다. 반면
전문적인 단어는 소수의 문서에서 발견될 것이며 더 높은 유사도 점수를 줄 수 있을 것이다. 이것을 수치화한게 IDF다. 예를 들어서 리눅스, 유저로 문서를 찾는다고 하면, 리눅스는 전문용어이므로 더 적은 문서에서 발견 될것이다. 일반적인 단어인 유저는 많은 문서에서 발견될 것이다. 그러므로 리눅스를 포함한 문서는 유저를 포함한 문서보다 더 높은 유사도를 부여할 수 있을 것이다. 매우 직관적인 생각이다.
예제 : 문서의 유사도
이렇게 각 문서에 대해서 Term Vector를 만들었다고 가정을 해보자.
이제 주어진 Term에 대해서 두 문서간의 거리를 구할 수 있게된다. 이 거리가 가까우면 더 유사한문서라고 할 수 있다.
눈으로 읽은 문서가 "야구기사"에 관련된 문서인지 "연예기사"에 관련된 문서인지 분리해낼 수 있는 인간과는 달리 컴퓨터는 이를
구분할 수 없다. 그렇기 때문에 이러한 Vector 모델을 만들어서 컴퓨터가 문서 유사도를 계산할 수 있게끔 하고 있다.
여기 A, B, C 세개의 문서가 있다고 가정해 보자. 그리고 백터에 위치하는 원소의 값을 다음과 같이 정의 하자.
- 번째 원소는 "상상플러스"라는 단어의 빈도수
- 번째 원소는 "김제동"
- 번째 원소는 "무한도전" 이다.
(A,B)는 상상플러스에 관한 문서이고, (C)는 야구에 관한 문서다. A에서 첫번째 원소인 "상상플러스"의 발생빈도는
10, "김제동"의 발생 빈도수는 5이다. B는 8,9이고, C는 0이라고 하면 다음과 같이 각 문서의 유사도를 계산해낼 수
있다.
- d(A,B) = 2^2 + 4^2 = 20
- d(A,C) = 10^2 + 5^2 = 125
- d(B,C) = 8^2 + 9^2 = 145
비슷한 주제의 문서들끼리 대체로 가까운 거리를 가지고, 다른 주제를 가지는 문서들이 거리가 멀이지는 것을 확인할 수 있을 것이다.
예제 : Query 에 대한 문서의 유사도
"리눅스"와 "개발자" 라는 단어를 포함한 문서들이 있다고 가정해 보자. 색인파일이 만들어져 있다면, 이들 문서를 포함한 문서를
찾는 것은 그리 어렵지 않을 것이다. 문제는 "리눅스"와 "개발자"를 포함한 수많은 문서중에서 더 많은 많은 관련성을 가진
문서를 어떻게 찾아내느냐에 있다.
쉽게 생각해서 문서 d 의 term vector가 만들어져 있다면, 각 term사이의 거리를 구한다음에 모두 더해주면 될 것이다.
- 리눅스는 매우 좋은 운영체제이다. 어쩌고 저쩌고.. 한참후에 개발자입장에서 한번 써볼한 하다.
- 리눅스는 개발자에게 매우 좋은 운영체제이다. 왜냐하면 어쩌고 저쩌고
간단한 거리계산을 이용해서 2번 문서가 주어진 Term들을 포함한 더 유사한 문서라는 걸 찾아낼 수 있다.
장점
- 동음이의어와 다의어 처리가 가능하다.
- 결과의 정확도 - relevance scoring - 를 구할 수 있다.
- 결과 피드백이 용이하다.
단점
Vector Space Model은 다음과 같은 단점을 가진다.
- Term의 갯수가 많아질수록 해당 문서는 더 낮은 similarity 값을 가지게 된다. 이는 큰 문서일 저 평가될 수 있음을 의미한다.
- 찾고자 하는 키워드가 정확히 매치되어야 한다. - 이 문제는 좋은 형태소 분석기를 가짐으로써 어느정도 해결할 수 있다. -
- 워낙에 광범위한 주제를 다루는 문서가 많고 문서에 포함된 Term의 양도 많기 때문에, 비슷한 주제를 다루는 문서라고 하더라도 전혀다른 Term으로 구성되는 경우가 발생한다.
- 느리다.
3번의 경우가 특히 문제가 될 수 있는데, 예를 들어서 설명해보도록 하겠다.
최홍만은 k-1에서 활약하는 격투선수이면서 특유의 쇼맨쉽으로 이런 저런 프로에 게스트 혹은 고정출현을 하고 있다. 그러므로 연예계 문서중 몇개에서는 ' 최홍만이 어느정도의 빈도수를 가지게 될 것이다. k-1 으로 눈을 돌려서 생각해보면, 최홍만이 출전한 경기와 관련된 문서의 경우 빈도수가 높지만, 그렇지 않은 경기와 관련된 문서인 경우 낮은 빈도수를 가지게 될 것이다.
이것을 가정해서 최홍만의 빈도수를 y축으로 k-1의 빈도수를 x축으로하고 연예방송과 k-1 두종류의 문서를 그래프로 그려보면 아래와 같이 각각의 주제가 y축으로 길게 늘어선 형태를 가지게 된다.
o = 연예계 문서 (k-1에 대한 단어가 전혀 나타나지 않음) x = k-1 관련 문서들 최홍만 |o x |o x |o x |o x |o x |o x +--------------> (K-1)
여기에서 다음의 결론을 얻을 수 있다.
- 같은 주제라고 하더라도 y축의 이쪽끝과 저쪽끝의 문서는 거리가 멀어진다.
- 다른 주제라고 하더라도 y축상에 있는 문서끼리는 거리가 가깝다.
- 결론 : 검색이 제대로 안된다 주제간의 차이를 반영하지 못하기 때문이다.
Markov random walk
더욱 문제가 되는 것은 주제의 성격이 비슷해서 원하는 문서를 가져오기가 애매모호해지는 경우다. 예를 들자면 리눅스관련 문서와 윈도우즈관련 문서쯤이 되겠다. 다음과 같은 그래프가 만들어진 경우를 생각해 보자.
(단어 2) ^ | o o o | o o o | o * x o x | o x x x | x x x | | -------------------------------------> (단어 1)
o = 주제 1에 속하는 문서들 x = 주제 2에 속하는 문서들 * = 쿼리
사용자가 *와 같은 쿼리를 줬을때, 올바른 결과는 주제 1에 속한문서들 중 쿼리와 가까이에 있는 문서가 상위에 올라오는 경우다.
그런데 그림을 보면 알겠지만 주제 2에 속하는 문서들중 몇개가 주제 1의 문서들보다 쿼리에 더 가까이 있기 때문에, 이들이
상위에 올라오는 문제가 발생한다. 이 경우 주제 2에 속하는 문서를 어떻게 제거할 것인가가 중요한 이슈가 될 것이다.
문제의 해결을 위해서 쿼리 근처 영역만을 잘라놓고 보도록 하자.
| o <-A | D-> o | C-> o * x <-B | o |
직선거리상으로만 보자면 A와 쿼리의 직선 거리가 B와 쿼리의 직선거리보다 멀다. - 기존 vector space 모델을 적용하게 되면, 거리가 가까운 B가 A보다 높은 유사도를 가질 것이다. - 그렇지만 쿼리와 C, 쿼리와 D, C와 D, D와 A 각각의 거리는 B의 거리보다 가깝다. 명확하지는 않지만 문제가 풀릴 수도 있다는 생각이 들 것이다. 각각의 포인트로 이동하게 될확률을 곱하는 것이다.
여기에서 확률은 거리에 따라 달라진다. 거리가 가까우면 움직일 확률이 높아지고, 멀면 그만큼 확률이 낮아진다. 이러한 문제를 처리하기 위해서 나온 아이디어가 Markov random walk로, 쿼리의 위치에서 시작을 해서 A 혹은 B로 도착할 때까지 매 턴마다 랜덤하게 임의의 포인트로 이동을 하는 방식이다.
예를들어 query에서 A로 갈수 있는 유망한 경로와 이에 따른 확률값은 다음과 같을 것이다.
- 쿼리 -> C -> D -> A : 확률값은 P(쿼리->C) * P(C->D) * P(D->A)
- 쿼리 -> D -> A : 확률값은 P(쿼리->D) * P(D->A)
- 기타 : 쿼리 -> C -> 쿼리 -> D -> A 등등등
해서 쿼리에서 A까지 도달할 확률은 위의 path들의 확률을 모두 더한게 될 것이다.
반면 쿼리에서 시작해서 B로 갈 수 있는 유망한 경로는 쿼리->B 하나 뿐이다. 쿼리에서 A 혹은 B로 이동하는 확률값은 각 포인트로 이동할 수 있는 확률의 곱이다. 이는 특정포인트로의 확률이 낮은게 있다면, 전체확률을 크게 낮추게 된다. 위의 그래프에서 C, D, A에서 B로의 거리는 너무 멀기 때문에 확률자체가 낮아지게 되고, 결국 다른 경로를 통한 확률은 쿼리->B보다 낮아질 수 밖에 없게 된다.
즉 두 문서간의 유사성을 판단할때 문서간의 직선거리를 생각하는 대신에 문서에 도착할 확률로 보는 것이다.
Markov Random walk 와 PageRank
PageRank는 문서의 중요도를 위해서 제시한 구글의 알고리즘이다. 예를 들자면 A, B, C, D 4개의 웹문서가 있고, 이중 B와 D가 A를 link 하고 있을 때, A의 Page Rank는
Q(A) = Q(B)/N(B) + Q(D)/N(D)
가 된다. N은 해당 페이지가 가지고 있는 link의 갯수를 의미한다. 이 계산을 모든 웹페이지에 대해서 반복해서 수행하면 된다.
여기에서 Markov Random walk 와 Page Rank와의 관계를 알아보자. 일단 Page Rank는 웹페이지 혹은
링크와 같은 것들을 따로 Vector화 하지 않는다. 그러므로 Markov Random walk를 사용할 수가 없다. 그렇다면,
여러개의 링크중 어떤 링크로 이동할 확률이 가장 큰가를 어떻게 계산할 수 있을까 ?
구글은 random click이라는 아이디어를 생각해 냈다. 예를 들어 A라는 웹페이에 N개의 링크가 있다고 가정 했을 때, random click란 그 중 하나를 무작위로 click할 확률을 의미한다. 이 확률의 계산은 무지 단순하다 1/N 하면 된다. 즉 위의 공식은 아래와 같이 좀더 자세하게 나타낼 수 있을 것이다.
Q(A) = Q(B)*(1/N(B)) + Q(C)*0 + Q(D)*(1/N(D)
Markov chain
우리는 확률과 관련된 공식을 이용해서 로또에
당첨될 확률, 교통사고를 당할 확률등을 알 수 있다. 주사위를 던졌을 때, 1이 나올확률이 1/6이라는 건 누구라도 알고 있을
것이다. 이러한 확률등은 다른 조건의 영향을 받지 않는다. 밤이건 낮이건 저녁이건 간에 주사위에서 특정 눈이 나올 확률은
1/6인 것이다. 서울에서 로또를 긁든 부산에서 긁든 간에 역히 확률은 동일하다.
그러나 실제 생활에서 발생하는 많은 사건의 확률은 여러가지 조건에 종속된 경우가 많다. 오늘의 비가 오지 않을 확률은 어제의
날시 상태가 어떠했는지에 따라서 달라질 수가 있다. 어제 해가 쨍쨍했는지, 달무리가 생겼는지 기타등등의 조건에 따라서 오늘 비가
올 확률이 변한다. 또한 오늘의 날씨의 상태는 내일 비가올 확률에 영향을 끼친다. 이렇게 주어진 조건에 따라서 확률값이 어떻게
변하는지를 분석하는게 Marcov chain 모형이라고 하며, 주어진 조건의 변화에 따라 변하는 확률값을 천이확률(Transition Probability)라고 한다.
lect_4.pdf
참고문헌
:::

이 문서는 수정될 수 있습니다. 최신 문서는 Joinc Wiki를 통해서 확인하세요. 몇 년간의 사이트관리 경험을 바탕으로 컨텐츠관리 노하우에 대해서 글을 써보려고 합니다. 양이 꽤 되기 때문에 나누어서 글을 쓸 계획입니다. 이글은 그 중 첫번째 글입니다.
컨텐츠의 영향력 확대
정보를 지배하는 자가 현재와 미래를 지배할 것이라는 얘기는 오래전부터 나왔지만 일반인 입장에서는 그리 와닿는 격언은 아니었던거 같다. 포탈, 인터넷 서비스회사와 같은 IT관련 업체나 실감하고 있었을 것이다.
그러던게 고속정보통신망이 일반화 되고, 구글과 같은 대량의 데이터를 처리할 수 있는 기반기술을
가진 회사가 나오면서 일반인들에게 까지 예전의 그 격언을 실감할 수 있게 되었다. 순수한 목적이든 아니든지 간에 컨텐츠확보가
부의 축적에 직접적으로 영향을 끼칠 수 있다는 것은 이제는 세삼스러운 얘기가 되었다. 인터넷 서비스 회사뿐만 아니라 개인도
컨텐츠를 확보하기 위해서 많은 노력을 기울이고 있다. 일반인의 컨텐츠확보 노력이 표면화 된게 UCC열풍쯤 되겠지 싶다.
중심에 서기
이제 일반인들도 보다 쉽게 자신의 컨텐츠를 배포할 수 있는 창구와 툴을 가지게 되었다. 인터넷, 초고속통신망, 각종 이미지및 동영상 저작툴과 이들을 쉽게 배포할 수 있는 블로그 그리고 가장 중요하다고 할 수 있는 검색엔진이 그것이다.
이게 흐름이라면 기왕이면 흐름의 중심에 서고자 하는 사람들이 생겨날 것이다. - 나 역시 그러한 사람 중 하나다 - 중심에 서기위한 키워드라면 창구와 툴의 효율적인 사용과 시대에 맞는 철학이 아닐까 싶다. 이들에 대해서 나름 가지고 있는 생각들을 얘기해 보려고 한다.
첫째도 둘째도 셋째도 컨텐츠
말할필요도 없다. 제아무리 좋은 사업아이템이 있어도 돈이 없으면 말짱 도루묵이듯, 제아무리 훌륭한 툴과 창구와 철학을 가지고 있다고 하더라도 컨텐츠가 없으면 아무 소용이 없다. 이를테면 컨텐츠는 총알이다.
보통 총알은 소비성인데 반해서, 컨텐츠는 (관리만 잘한다면) 소비성이 아니라는 크나큰
장점도 가지고 있다. 사업자금 떨어지면 낭패지만 컨텐츠는 마음먹고 꾸준히 쌓아간다면 그 결과가 표면화 되는 시점이 반드시 오게
되어 있다. 적어도 손해는 보지 않는다. - 투자한 시간대비 얻는게 없으면 손해라고 할 수도 있겠지만, 이건 그러려니 하고
넘어가도록 하겠다 -
전문적이든 아니든간에 일단 컨텐츠를 만드는 시도를 해보기 바란다. 컨텐츠가 없는 상태에서 이렇게 저렇게 요렇게 최적화 하면 최고더라. 메뉴를 이렇게 구성해야 한다! 아니다! 하는거 전부 뜬구름잡는 이야기일 뿐이다. - 시작초기라면 - 온라인상에 떠도는 무슨무슨 최적화 이런거 신경쓰지 말기 바란다. 서당개 3년이면 풍월을 읊는다고 컨텐츠관리 1년이면 누가 알려주지 않아도, 온라인상에 알려진 수준의 최적화 기법들은 저절로 터득하게 되어있다.
위키와 블로그를 활용하라
컨텐츠의 축적과 배포수단으로 블로그의 활용은 대세인거 같다. 덧붙이자면 wiki의 활용을 적극적으로 권장하는 바이다. 블로그는 웹로그의 성격을 가진 매체이다. 이런 특징이 개인미디어로의 활용을 좋게하기는 하는데, 나름대로의 문제점이 있다. 그것은 이미 만들어진 컨텐츠가 멈추어버린다는 거다. 멈추어 있으니 시간이 지나면 지날 수록 컨텐츠의 중요도가 점점 떨어지게 된다.
반면 위키는 웹로그가 가지는 장점을 가지지 못한대신에 컨텐츠를 지속적으로 관리할 수 있다는 장점을 가진다. 지식기반 시스템을 위해서 위키를 사용하는 이유이고, 가장 성공한 케이스가 wikipedia일 것이다.
개인적으로 추천하는 방식은 블로그로 소통을 하고 위키로 컨텐츠를 체계적으로 관리해서 지식정보화 시키는 방식이다. 우리나라에서는 찾아보기 어렵지만 외국에서는 꽤나 일반적인 방식이기도 하다.
이 방식의 또다른 장점은 컨텐츠의 배포경로를 두군대로 할 수 있다는데 있다. 배포경로가 다양하다는 것은 검색이 더 잘된다는 것 이상의 의미를 가진다.
블로그컨텐츠와 웹문서로 분류될 수 있는 위키컨텐츠는 문서의 중요도가 산정되는 방식에 있어서 많은 차이를 보인다. 구글검색을 보더라도 블로그검색과 웹문서검색은 분명하게 구분되어 있다. 블로그문서는 웹로그라는 특성상 시간문서의 중요도를 위한 가장큰 계산요소중 하나다. 이를테면 휘발성 컨텐츠라는 개념이 강한게 블로그 컨텐츠이다. 시간이 지날 수록 문서의 중요도가 계속적으로 떨어진다
제아무리 좋은 문서를 만들었다고 해도 시간이 지나서 문서가 검색되지 않는다면, 컨텐츠의 역할을 한다고 볼 수 없습니다.
웹문서는 지속성개념의 컨텐츠다. 오래된 문서일 수록 더 많은 링크가 발생하고, 삭제되지
않는한 계속적으로 가치가 올라가게 되어 있다. 가치를 지속적으로 상승시키고 싶은 컨텐츠가 있다면, 위키와 블로그 양쪽 모두를
통해서 문서를 배포하기 바란다. 개인이 위키사이트를 관리하기 힘들다면 스프링노트와 같은 위키서비스를 이용하면 될 것이다.
이글을 쓰는 필자역시 위키로 관리하고 블로그로 배포하는 방식을 사용하고 있다. 위키를 오래 사용해서, 많은 데이터가 위키를 통해서 관리되었던 이유도 있지만 말이다.
검색엔진 최적화
SEO라고도 하는데, 이건 어느정도 컨텐츠가 축적되어 있어야지 효과를 볼 수 있는 방법이다.
SEO는 검색엔진의 특징을 이용해서 문서를 훼손하지 않는 범위에서 검색결과 상위에 노출되도록 하는 기술을 말한다. 돈을 벌려면 금융시스템을 잘 알 수록 유리한것과 마찬가지가 되겠다.
다음의 공식을 이해하면, SEO를 8할쯤 마스터한거라고 볼 수 있다. 나머지는 응용이다.
문서의 점수 = tf * idf
아주 단순한 공식이다. tf는 문서에 발생한 해당 단어의 갯수이고, idf는 단어를 포함한 문서의 갯수다.
리눅스를 포함한 문서를 찾는다고 하면, 리눅스라는 단어를 많이 포함한 문서일 수록 더 중요한 문서일것이라고 가정할 수 있을 것이다. 매우 직관적이다. 이 것을 수치화 한게 tf이다.
전문적인 단어는 적은 문서에서 나타날 것이다. 반면 일반적인 단어는 많은 문서에서 발생할 것이다. 즉 해당단어를 포함한 문서가 적으면 더 높은 점수를 줄 수 있다는 결론에 도달한다. 이것을 수치화한게 idf이다. 예를 들어 그 리눅스로 검색을 한다면, 그와 리눅스 모두를 포함한 문서가 가장 높은 점수를 받고, 그 다음으로 리눅스만 포함한 문서가 높은 점수를 받을 것이다. 아주 일반적인 단어인 그만 포함한 문서는 밑으로 깔릴 것이다.
이 상에서 다음과 같은 SEO 기법들을 생각해 낼 수 있다.
- 키워드가 자주 발생하게 한다. tf를 높이겠다는 얘기가 되겠다.
리눅스와 윈도우의 차이점에 대해서 얘기를 하겠다. 전자는 후자에 비해서 이런이런 장점을 가지고 있다이런식으로 작성하는 것보다는
리눅스와 윈도우의 차이점에 대해서 얘기를 하겠다. 리눅스는 윈도우에 비해서 이런이런 ...식으로 키워드를 자주 노출시키도록 한다.
- 전문분야에 대한 컨텐츠를 많이 작성한다. idf를 높일 수 있다.
- 문서의 제목과 URL은 신중하게 결정한다.
웹문서는 제목, 본문, URL의 3가지 요소로 구성된다. 똑같은 단어라도 어떤 요소에서 발생했는가에 따라서 부여하는 점수가 틀리다. URL > 제목 > 본문 순이다. 그러므로 URL과 제목은 그 문서를 특징할 수 있는 단어를 포함하게 해야 한다. 그것도 가능하면 2번이상 포함하게 한다.
리눅스를 사용하자 라는 제목보다는 리눅스? 리눅스의 활용처가 궁금하다라는 식으로 제목을 작성하는게 좋다.
- URL과 제목은 간략하게
단어의 갯수가 많아질수록 점수가 떨어진다. 여러분 리눅스를 사용하면 어떤 점이 좋을지 궁금하지 않으세요?" 보다 리눅스를 사용하자'''가 더 좋은 제목이다. 메타블로그에도 노출시킬 거라면, 후자가 반드시 좋은방법이라고 보기는 힘들것이다. 적절한 제목을 부여하도록 하자.
링크를 이길 수는 없다
그러나 위의 tf * idf에 기반한 검색엔진 최적화는 링크를 이길 수 없다.
tf * idf? 그렇다면 다음과 같이 tf'를 늘리는 소위 낚시성 웹페이지를 만들 수 있을 거라고 생각할 수 있을 것이다.
애플 아이폰, 애플 아이폰, 애플 아이폰, 애플 아이폰 .... 한 100번쯤 반복
실제 저런 식의 낚시성 사이트들이 꽤 있다. tf*idf 의 취약성을 공격하는건데, 취약한 검색엔진 알고리즘을 가진 사이트의 경우에는 저런 웹페이지가 top으로 검색되는걸 볼수 있다.
하지만 최근의 검색엔진들은 pagerank와 같은 링크기반의 웹페이지 중요도산정 기술들을 도입하고 있기 때문에 저런식의 낚시사이트는 잘 검색되지 않는다. 이들 기술은 중요한 페이지 일 수록 많은 웹페이지들로 부터 링크 되어 있을 것이다라는 가정에서 출발한다. 그래서 페이지의 링크를 계수해서 문서의 스코어를 결정한다. 즉 공식은 다음과 같이 수정될 수 있을 것이다.
문서 중요도 = (tf * idf) * pagerank
위 공식에서 pagerank가 상당히 높기 때문에 낚시사이트가 상위페이지에 검색이 안되는 것이다.
아래는 pagerank의 개념을 보여주는 그림이다.
C는 A와 B문서로 부터 링크를 가지고 있고, 이 링크의 점수를 모두 더해서 PageRank가 계산된다. 물론 링크라고해서 다
같은 점수를 가지고 있는건 아니다. 중요도가 높은 문서로부터 링크가 되어 있다면 더 높은 점수를 가지게 된다.
결국, 다른 웹페이지들로 부터 링크를 당할? 만큼의 좋은 문서를 만드는게 가장 우선이 됨을 알 수 있다. tf * idf를 통한 최적화는 비슷한 수준의 문서끼리 경쟁할때나 써먹는 것이다. 이를테면 링크는 온라인상의 표라고 보면 될 것이다. 일단 표를 획득해야 뭘하든지 해먹을거 아닌가.
이쯤에서 눈치빠른 독자라면 또다른 최적화 포인트를 찾았을 것이다. 바로 높은 페이지랭크를 가진 사이트에 자신의 페이지를 가리키는 링크를 만드는 것이다. 양질의 컨텐츠를 가진 사이트와 커뮤니케이션 하라는 얘기가 되겠다. 링크를 통한 커뮤니케이션은 게시판등을 통한 링크, 트랙백등을 통해서 이루어지도록 할 수 있을 것이다.
문서를 작성했다면 나루 블로그검색, 웹검색 서비스등을 이용해서 자신의 문서와 관련있는 좋은 문서를 찾아서 적극적으로 커뮤니케이션 하기 바란다. 특히 나루의 생각부자는 자신의 문서와 관련있는 문서를 찾기위한 매우 좋은 서비스다.
근데, 이런걸 꼭 나쁜쪽으로 써먹는 부류의 사람들이 있다. 스팸을 남발하는 부류의 사람들이다. 지금도 여러분의 게시판과 포스트에는 스팸댓글과 스팸트랙백이 달리고 있을 것이다. 커뮤니케이션의 도구로 사용할지 스팸으로 사용할지는 여러분의 행동에 달려있다.
자주 꾸준히 포스팅 하라
위의 방식은 웹검색에서는 매우 유용하게 사용될 수 있지만 블로그검색은 많은 차이가 있다. 시간을 중요시하는 웹로그시스템이기 때문이다. 시간이 가장큰 점수산정 요소이므로 가능한 부지런히 포스팅 하는게 좋다.
혹시 기존의 웹문서 컨텐츠를 블로그로 옮길 계획이라면 하루에 수백건씩 몽땅 올리는우를 범하지 말기 바란다. 느긋하게 하루에 2-3개씩 정도를 포스팅 하도록 하자.
블로그에서의 문서 중요도는 시간과 채널 중요도에 따라서 결정이 된다. 채널 중요도는 이 블로그가 얼마나 포스팅을 열심히 하는가로 결정하는데 하루에 수십-수백개씩 올리면, 이 채널은 뉴스사이트 혹은 메타사이트정도로 인식이 되어서 채널중요도가 떨어지게 된다. 그러므로 꾸준히 올리는게 중요하다.
오늘은 여기까지 하겠습니다. 다음번에는 사이트내에서의 검색을 통한 최적화에 대해서 알아보겠습니다. :::

|
우리나라는 심지어는 포탈이라고 하더라도 링크가 깨지던 말건 상관없이 커텐츠를 몽땅 들어올리는 경우가 흔합니다. 뭐.. 포탈안에서만 검색되면 된다라는 생각에서 대수롭지 않게 여긴결과인지도 모르겠지만, 컨텐츠에 대한 인식이 아직은 후진적이기 때문이라는 생각이 듭니다.