database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
ㆍPostgreSQL
Firebird
Oracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
PostgreSQL Devel 4165 게시물 읽기
 News | Q&A | Columns | Tutorials | Devel | Files | Links
No. 4165
plpython 이용하기 + full text index
작성자
김상기(ioseph)
작성일
2002-04-25 00:52ⓒ
2003-09-03 23:27ⓜ
조회수
12,177

0. 문제의 발단.

 

postgresql 소스의 contrib 안에는 fulltextindex와 tsearch 모듈이 있는데, 이놈들이 한글환경에 그리 적합하지 않습니다.

 

한글 환경에 맞는 full text index 기능의 가장 완벽한 방법은

C로 contrib 안에 있는 fulltextindex 놈 같이 한글환경에 맞게 새로 만드는 것이고, 다음은,

contrib 안에 있는 fulltextindex 놈을 한글 환경에 맞게 수정하는 것이고,

그다음은 fulltextindex 알고리즘을 흉네내서 다른 pl 언어로 만드는 것이겠지요.

 

그래서, 첫번째 시도했던 것이 plpgsql 놈이였는데, 이놈이 문자열 처리에 그리 쉽지 않은지라, 그래서, 두번째로 시도했던 것이 plpython 이었습니다. (plperl도 가능하겠지만, 개인적으로 perl보다는 python 놈을 선호하는 편이라서)

 

여기서 설명하는 것은 postgresql 7.2.1, python 2.1.3 대상으로 했습니다.

(python 2.2.1 에서는 re 모듈 임포팅이 안되는군요. 개발자가 2.1.x 이하 버전에서 개발했나봅니다. 이 문제는 아마 다음 버전에서 해결나지 않을까싶네요)

 

 

1. plpython 만들기 및 설치

 

postgresql 서버를 만들때, configure 에서 --with-python 옵션을 추가해 두고, 서버를 설치하면, lib/ 디렉토리 안에 plpython.so 파일이 생깁니다.

(python 2.2.1 과 1.5.x 버전이 같이 있다면, configure 사용할 때, 잠깐 python 2.2.1의 실행파일 이름을 python 으로 해둡니다. 그래야, 2.2.1의 모듈들을 이용할 수 있습니다)

 

 

2. db에 설치하기,

 

$ createlang plpython dbname

이런식으로 설치하고,

$ createlang -l

명령으로 확인해 보실 수 있습니다.

$ createlang -l
Procedural languages
   Name   | Trusted?
----------+----------
 plpgsql  | t
 plpython | t
(2건 있음)

 

 

3. plpython 으로 구현한 fulltextindex 트리거

다음은 제가 plpython으로 오늘 처음 만들어본 plpython의 함수와, 그것을 이용한 트리거입니다.

 

---------

-- t_fti() 트리거용 함수 정의 plpython 으로
-- 만든이: 김상기 
-- 저작권: 이 모듈은 제작자의 동의를 구하지 않은 무단복제를 널리 권장합니다.
-- $Id: ftipy.sql,v 1.1 2002-04-24 23:24:51+09 ioseph Exp $

CREATE FUNCTION t_fti() RETURNS opaque AS '
import re;
if TD["event"] == "INSERT":
  arr = re.split("[ \n\t\r]+", TD["new"][TD["args"][2]]);
  for strkey in arr:
    if strkey != "":
      strkey = re.sub("[''"]", "", strkey);
      s = "insert into %s values (''%s'',''%s'')" % (TD["args"][0], TD["new"][TD["args"][1]], strkey);
      plpy.execute(s);
if TD["event"] == "DELETE":
  s = "delete from %s where num  = ''%s''" % (TD["args"][0], TD["old"][TD["args"][1]]);
  plpy.execute(s);
if TD["event"] == "UPDATE":
  s = "delete from %s where num  = ''%s''" % (TD["args"][0], TD["old"][TD["args"][1]]);
  plpy.execute(s);
  arr = re.split("[ \n\t\r]+", TD["new"][TD["args"][2]]);
  for strkey in arr:
    if strkey != "":
      strkey = re.sub("[''"]", "", strkey);
      s = "insert into %s values (''%s'',''%s'')" % (TD["args"][0], TD["new"][TD["args"][1]], strkey);
      plpy.execute(s);
return None;
' LANGUAGE 'plpython';

-- 트리거 정의
CREATE TRIGGER t_fti
  AFTER INSERT OR UPDATE OR DELETE
  ON ftimain
  FOR EACH ROW EXECUTE PROCEDURE t_fti('ftidata', 'num', 'body');

--------------

 

웹에서 올라오는 글인지라, 잘 읽으셔야합니다. :)

 

 

4. 이놈의 사용법

 

ioseph=# \dt+
                   List of relations
  Name   | Type  | Owner  |        Description
---------+-------+--------+----------------------------
 ftidata | table | ioseph | ftimain 에서의 그 인덱스들
 ftimain | table | ioseph | fti 연습용 자료테이블
(2 rows)

ioseph=# \d ftimain
                            Table "ftimain"
 Column |  Type   |                      Modifiers
--------+---------+-----------------------------------------------------
 num    | integer | not null default nextval('"ftimain_num_seq"'::text)
 body   | text    |
Unique keys: ftimain_num_key
Triggers: t_fti

ioseph=# \d ftidata
       Table "ftidata"
 Column |  Type   | Modifiers
--------+---------+-----------
 num    | integer |
 ftikey | text    |
Indexes: ftidata_ftikey_i

 

이렇게 두 테이블을 만들고, 관련 인덱스를 만듭니다.

다음, 위에서 언급한 function을 만들고, trigger도 설정해둡니다.

 

ioseph=# select * from ftimain;
 num |        body
-----+---------------------
  41 | 지를 왜 '좋아'해유?
(1 row)

ioseph=# select * from ftidata;
 num |  ftikey
-----+-----------
  41 | 지를
  41 | 왜
  41 | 좋아해유?
(3 rows)

 

full text indexing에 관심있으신 분은 이제 분위기가 파악되었을겝니다.

 

이것으로 뭘하는가?

ioseph=# EXPLAIN ANALYZE SELECT a.* FROM board a, board_fti_title b WHERE b.ftikey LIKE '안녕%' AND a.num = b.num;
NOTICE:  QUERY PLAN:

Nested Loop  (cost=0.00..41.25 rows=5 width=40) (actual time=0.16..0.18 rows=1 loops=1)
  ->  Index Scan using board_fti_keyi on board_fti_title b  (cost=0.00..17.07 rows=5 width=4) (actual time=0.09..0.10 rows=1 loops=1)
  ->  Index Scan using board_num_key on board a  (cost=0.00..4.82 rows=1 width=36) (actual time=0.05..0.06 rows=1 loops=1)
Total runtime: 0.48 msec

EXPLAIN

 

이렇게 쓰입니다.

 

 

5. 마침말

 

제가 게을러서 보기 좋게 문서화 하지 않음에 대해서 양해를 구합니다.

[Top]
No.
제목
작성자
작성일
조회
5297crypt 함수 구현하기 [1]
이상호
2004-04-17
10466
42301차원 정수형 배열 조작 함수들 [1]
김상기
2002-06-17
12968
4223PL/pgsql로 구현한 fulltext index
김상기
2002-06-11
13991
4165plpython 이용하기 + full text index
김상기
2002-04-25
12177
3544PostgreSQL 응용 프로그램 작성하기 (V)
정재익
2001-10-18
13118
3537PostgreSQL 응용 프로그램 작성하기 (IV)
정재익
2001-10-18
11859
3536PostgreSQL 응용프로그램 작성하기 (III)
정재익
2001-10-18
11024
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2023 DSN, All rights reserved.
작업시간: 0.050초, 이곳 서비스는
	PostgreSQL v16.1로 자료를 관리합니다