'PHP'에 해당되는 글 8건

  1. 2011.09.20 경향신문 기사 검색엔진 1
2011. 9. 20. 11:02

경향신문 기사 검색엔진

경향신문 기사 검색엔진

<이진우씨..www.jinux.pe.kr>

(간만에 자료 참조 할려고 사이트들어가봤는데.. 도메인연장 안돼서 ..옮겨놓습니다.)

 

 

 

1. 개발 환경
OS : Linux
웹서버 : httpd-2.0.52
개발언어 : php-4.3.10
사용데이타베이스 : mysql-standard-4.0.23-pc-linux-i686.tar.gz (바이너리 버전)
미들웨어 : sqlrelay-0.36.1
유틸리티 : ImageMagick-5.5.6 (섬네일 이미지를 위하여)

 

2. 데이타베이스 스키마


기사 테이블
CREATE TABLE khan_article (
  no int(10) unsigned NOT NULL auto_increment,
  art_id varchar(16) NOT NULL default '',
  sec_id varchar(6) NOT NULL default '',
  med_id varchar(4) NOT NULL default 'khan',
  art_title varchar(128) NOT NULL default '',
  art_body text NOT NULL,
  is_image enum('n','y') NOT NULL default 'n',
  is_index enum('n','y','u','d') NOT NULL default 'n',
  PRIMARY KEY  (no),
  KEY art_id (art_id),
  KEY sec_id (sec_id),
  KEY med_id (med_id),
  KEY is_image (is_image),
  KEY is_index (is_index)
) TYPE=MyISAM;

 

역인덱싱 테이블
CREATE TABLE khan_word_0 (
  no int(10) unsigned NOT NULL auto_increment,
  word varchar(64) binary NOT NULL default '',
  wordcount int(10) unsigned NOT NULL default '0',
  wordtxt mediumtext NOT NULL,
  PRIMARY KEY  (no),
  UNIQUE KEY word (word),
  KEY wordcount (wordcount)
) TYPE=MyISAM COMMENT='경향기사 워드테이블0';
...
CREATE TABLE khan_word_9 (
  no int(10) unsigned NOT NULL auto_increment,
  word varchar(64) binary NOT NULL default '',
  wordcount int(10) unsigned NOT NULL default '0',
  wordtxt mediumtext NOT NULL,
  PRIMARY KEY  (no),
  UNIQUE KEY word (word),
  KEY wordcount (wordcount)
) TYPE=MyISAM COMMENT='경향기사 워드테이블9';

 

검색 불필요 단어 테이블
CREATE TABLE nose_word (
  no int(10) unsigned NOT NULL auto_increment,
  word varchar(64) binary NOT NULL default '',
  wordcount int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (no),
  UNIQUE KEY word (word),
  KEY wordcount (wordcount)
) TYPE=MyISAM COMMENT='검색 불필요 단어';

 

핫 키워드 테이블
CREATE TABLE top_keyword (
  serial int(10) unsigned NOT NULL auto_increment,
  imp_date date NOT NULL default '0000-00-00',
  imp_keyword varchar(32) binary NOT NULL default '',
  imp_count int(11) NOT NULL default '0',
  is_open enum('y','n') NOT NULL default 'y',
  PRIMARY KEY  (serial),
  KEY imp_date (imp_date),
  KEY imp_keyword (imp_keyword),
  KEY imp_count (imp_count),
  KEY is_open (is_open)
) TYPE=MyISAM COMMENT='핫키워드';

 

단어 사전
CREATE TABLE word_dic (
  no int(10) unsigned NOT NULL auto_increment,
  word varchar(64) binary NOT NULL default '',
  PRIMARY KEY  (no),
  UNIQUE KEY word (word)
) TYPE=MyISAM COMMENT='키워드 사전';

 

3. 개발


khan_article 에 모든 기사를 넣는다.
주기적으로 업데이트되는 기사와 삭제된 기사를 처리 한다.

기사의 제목과 본문을 불러와서 특수문자, 스페이스(STOP WORD) 로 분리한다.
분리한 단어의 처음 2바이트를 불러와서 해당 테이블에 넣는다.

 

function get_magic_number($str)
{
 return ((ord($str[0]) + ord($str[1]))%10);
}


함수에 넣어 0 에서 9 까지의 값을 받아 10개의 테이블에 단어가 골고루 분포 하도록 한다.

가령 magic_number 가 "5" 이고 해당 단어가 "대통령" 이고 기사의 ID 가 "19500520245" 이고 기사 섹션코드가 100 일때
khan_word_5 테이블을 사용하여
word 에는 "대통령" 
wordtxt 에 19500520245100 가 존재 하지 않으면 wordcount ++, 존재 하면 넣지 않는다.

사용자가 "대통령" 이라는 단어를 검색하면 khan_word_5 테이블의 "대통령" 의 wordtxt 를 가져와 배열에 넣고 array_unique 로 중복을 제거하고 
array_multisort ($art_id, SORT_DESC); 로 날짜 순서로 배열 시킨후 페이지에 보여 준다.
이때 기사 본문중 "대통령" 이라는 단어를 하이라이트 시킨다.

이때 "대통령" 이라는 단어를 찾을때 like '대통령%' 로 검색을 하므로 당연히 인덱스를 탄다.

당연하지만 "대통령" 이라는 단어를 검색하면 "대통령은" , "대통령에게"... 등과 같은 단어도 같이 검색이 된다.
또 당연하지만 "대통령은" 이라고 검색을 하면 "대통령" 단어는 검색되지 않는다.

만약 사용자가 "한국의 힘" 이런식으로 여러 단어를 입력했을 때는 두개의 테이블에서 각각 위와 같은 방법으로 데이타를 가져온 후

 

$art_id1 = array_unique($art_id1);
$art_id2 = array_unique($art_id2);

  
// 두개의 어레이에서 공통으로 들어간 부분을 찾아낸다.
$inter_array = array_intersect ($art_id1, $art_id2);


// 두개의 어레이에서 공통이 아닌 것을 찾아낸다.
$diff_array1 = array_diff  ($art_id1, $art_id2);
$diff_array2 = array_diff  ($art_id2, $art_id1);

 

// 공통인 것을 먼저 공통이 아닌것을 나중에 배열시킨다.
$diff_array = array_merge($diff_array1, $diff_array2);
array_multisort ($inter_array, SORT_DESC);
array_multisort ($diff_array, SORT_DESC);

$art_id = array_merge ($inter_array, $diff_array);

 

 


와 같이 배열을 시켜 두개의 모든 단어가 있는 기사를 먼저 배치 시키고 "한국의" 혹은 "힘" 이라는 단어가 들어가 있는 기사는 나중으로 배치 시킨다.

 

 

4. TIP
F5 키를 마구 눌러 데이타 베이스에 부하가 가는 것을 염려해서 미들웨어인 sqlrelay-0.36.1 를 사용했다.
섬네일 이미지를 위해 ImageMagick-5.5.6 사용했다.
해당 기사에 있는 첫번째 이미지의 가로와 세로 비율이 0.6 ~ 1.8 이내에 있는 이미지만 가져오도록 했다.
(가로 세로의 비율이 너무 심한 이미지는 리스트 페이지가 보기 않좋아 지므로...)

 

5. TO DO
시간 관계상 인덱싱 데몬을 PHP 로 짰더니 인덱싱 속도가 너무 느리다. C 로 다시 짜야 할 것 같다.
ImageMagick-6.2.3 은 make 과정에서 에러가 계속 생겨 ImageMagick-5.5.6 를 사용했다. 
개발 시간이 부족한 관계로 어디서 왜 설치 에러가 발생하는지 조사하지 못했다.
ImageMagick-5.5.6 은 configure 와 make 는 무사히 넘어 갔으나 make install 과정 후반에서 에러가 발생한다.


역시 시간이 부족한 관계로 왜 어떤 이유로 에러가 발생했는지 조사하지 않았다.
다행히도 내가 원하는  convert 실행 파일이 생긴 후에 에러가 발생했기 때문에 make install 을 완료 해야하는 수고를 하지 않았다.
내가 원하는 건 해당 이미지의 URL 을 주면 조그만 섬네일 이미지를 만들어 주는 convert 뿐이기 때문이다.
유사어에 대한 고민을 해 보았다. 하지만 "반지의 제왕"라고 검색을 하고 "가락지의 제왕" 이라는 검색 결과를 기대하는 사람은 별로 없을 것이라 판단해서
과감히 포기를 했다.
간혹 여러 단어지만 띄여쓰기를 하지 않고 검색을 하는 경우가 있다.
가령 "반지의제왕", "박지성이영표", "루루공주김정은" 과 같은 경우 이다.
한글 사전을 사용하지 않기 때문에 어쩔 수 없이 포기 하려 했다.
하지만 불행히도 네이버 검색에서는 "반지의제왕", "박지성이영표", "루루공주김정은" 이렇게 검색을 해도
"반지의 제왕", "박지성 이영표", "루루공주 김정은" 의 검색 결과가 나온다.

 

할 수 없이 간단한 한글 사전을 만들 수 밖에 없었다.

완벽한 한글 사전이 아니라서...
"노 대통령" 이라고 검색을 했을때

부시 측근감싸기 ‘점입가경’ 
... 백악관 비서실 부실장에 대해 기자들이 묻자 “그는 나로부터 완전한 신뢰를 받고 있으며 내 팀의 소중한 멤버”
라고 노골적으로 감쌌다. 〈워싱턴|정동식특파원... ...지 부시 미국 대통령의 마이동풍식 ‘측근 
두둔’은 끝이 없다. 부시 대통령은 1일 텍사스지역 신문들만 백악관으로 초청, 기자회견을 열었다. 그는 이 자리에서 기자... 
[국제/미국·중남미] 2005.08.03. 18:13:28

이라는 검색 결과가 나오는게 맞는건지 아닌건지... 떱...

 

word_dic 이라는 테이블인데 여기에 몇몇 주요 단어를 넣어서 처리를 하였다.
앞으로 신조어가 발생하면 이 테이블에 단어를 넣어 주는 수고는 해야 할 것 같다.
하지만 단어에 의한 역 인덱싱 방식을 사용하므로 "핑클" 을 검색 했을 때 "서핑클럽" 이 검색되는 일은 없다.

 

여담 이지만 검색 단어를 문장 중간에 하이라이트 시키려고 하는 부분에서 고생을 많이 했다. 
검색단어가 기사의 제일 처음이라 혹은 마지막에 위치하는 경우 더하기 빼기가 너무 어려웠다.

PS : 제대로 된거 만들어야 하는데 아직 할일이 많다......