sphinx #4 :: 스핑크스 주기적 인덱스 방법 (delta + crontab)
오픈소스 검색엔진 뭐 사용할까? 가벼운 스핑크스(Sphinx) 사용해보자 (인트로)
Sphinx #1 :: 스핑크스 설치 및 환경설정
sphinx #2 :: 스핑스크 쿼리 테스트 (sphinxQL + PHP연동)
sphinx #3 :: MySQL에서 스핑크스 직접 join하기 (sphinxSE)
sphinx #4 :: 스핑크스 주기적 인덱스 방법 (delta + crontab)
스핑크스의 인덱스 순서는 아래와 같습니다.
- 환경설정 : sphinx.conf
- 인덱스 실행 : indexser --all
- 데몬 실행 : searchd
- 인덱스 재 실행 : indexser --all -- rotate (searchd 실행중인 경우에는 --ratate 옵션 부여)
그럼 인덱스 실행은 얼마나 자주 해야 하는걸까요?
실시간으로 응대해야 한다면 전혀 다루지 않았던 RT형식으로 해야 할 겁니다.
제가 구현하고자하는 통합검색에는 실시간까지는 필요 없고 그래도 최대 1~5분 주기로는 인덱스 작업을 해줘야 합니다.
그러나 테이블 하나가 100만 건만 된다고 하더라도 인덱스하는 시간이 수분~수십분이 걸립니다.
100만건 되는 테이블이 다수개라면 서비스 자체가 할 수 없게 됩니다.
이를 해결하기 위해서 아래와 같이 인덱스 실행 스케쥴을 잡습니다.
- 최초 한번은 전체 인덱스 실행한다.
- 특정 주기(1~5분)마다 부분 인덱스를 실행한다.
- 부분 인덱스 테이블과 전체인덱스 테이블을 합친다.
- 특정 주기(1일~1주일) 마다 전체 인덱스를 실행한다.
- 2번 ~ 4번을 반복한다.
바로 구현해보도록 하겠습니다.
Delta index updates
만약 10,000,000개의 데이터가 저장된 게시물이 있고,
하루에 1,000개의 새 게시물이 발생되는 게시판이 있다고 가정해봅시다.
이런 경우 "main + delta" 체계를 구현할수 있도록 스핑스크에서 제공하고 있습니다.
우선 mysql에 테이블을 생성합니다.
새로 추가된 row를 알 수 있도록 해주는 테이블을 하나 생성합니다.
# mysql에서 진행합니다.
# 스핑크스 DB 이동 ( [sphinx #3 :: sphinxSE 사용하기] 편에서 만들었었죠 )
mysql> use sphinx;
# 테이블 생성
mysql> CREATE TABLE `config_max_id` (
`source_name` varchar(30) NOT NULL COMMENT '스핑크스 소스이름',
`max_id` int(10) unsigned NOT NULL COMMENT '해당테이블 max PK 값',
`edit_date` datetime DEFAULT NULL COMMENT '수정일',
PRIMARY KEY (`source_name`),
KEY `idx_sph_type` (`source_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='스핑크스 delta 제어 테이블';
다음으로 스핑스크 환경설정(shphinx.conf)을 수정 및 추가합니다.
]$ vi /etc/sphinx/sphinx.conf
#############################################################################
## source settings
#############################################################################
source sph_zip_code
{
type = mysql
sql_host = mysql ip주소(localhost)
sql_user = 계정명
sql_pass = 패스워드
sql_db = DB명
sql_port = 3306
sql_query_pre = SET NAMES utf8
sql_query_pre = SET SESSION query_cache_type=OFF
sql_query_pre= REPLACE INTO sphinx.config_max_id SELECT 'sph_zip_code', MAX(seq), now() FROM test.zip_code
sql_query = \
SELECT seq, zip_code, add1, add2, add3, address \
FROM zip_code \
WHERE seq <= (SELECT max_id FROM sphinx.config_max_id WHERE source_name='sph_zip_code' )
sql_field_string = zip_code
sql_field_string = add1
sql_field_string = add3
sql_field_string = address
}
source sph_zip_code_delta : sph_zip_code {
sql_query_pre = SET NAMES utf8
sql_query_pre = SET SESSION
query_cache_type=OFF
sql_query = \
SELECT seq, zip_code, add1, add2, add3, address \
FROM test.zip_code \
WHERE seq > (SELECT max_id FROM sphinx.config_max_id WHERE source_name='sph_zip_code' )
}
#############################################################################
## index settings
#############################################################################
index sph_zip_code
{
source = sph_zip_code
path = /var/lib/sphinx/data/sph_zip_code
docinfo = extern
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
ngram_len = 1
min_infix_len = 2
ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6
}
index sph_zip_code_delta : sph_zip_code
{
source = delta
path = /var/lib/sphinx/data/sph_zip_code_delta
}
빨간 부분이 수정 또는 추가된 부분입니다.
source sph_zip_code 에서 sql_query 실행하기 전에 zip_code의 max(seq) 값을 위에서 config_max_id 테이블에 update 시켜놓았습니다.
sph_zip_code_delta 는 1~5분 마다 실행되도록 cron에 설정할 예정이고,
이는, config_max_id 테이블에 저장되어 있는 max(seq) 보다 큰 데이터만 인덱스를 실행하게 됩니다.
전체 인덱스를 실행합니다.
]$ indexer --all -rotate
이렇게 하면 sph_zip_code, sph_zip_code_delta 둘 다 실행됩니다.
다음으로 부분 인덱스를 실행합니다.
# 부분 인덱스 실행
]$ indexer sph_zip_code_delta --rotate
# 원형과 delta를 병합합니다.
]$ indexer --merge sph_zip_code sph_zip_code_delta --rotate
crontab 등록
크론에는 당연히 두개를 등록해야 합니다.
한개는 전체 인덱스 설정이고,
다른 하나는 부분 인덱스 설정입니다.
[전체 인덱스]
]$ mkdir /etc/sphinx/bin
]$ vi /etc/sphinx/bin/all_update.sh
스크립트 파일 생성후 아래와 같이 전체 인덱스 실행 명령어 기술하고 저장합니다.
#!/bin/bash
indexer --all --rotate
스크립트 파일 권한 부여 후 테스트 해보시고 잘 동작 잘 되는지 테스트합니다.
# 권한 부여
]$ chmod 755 /etc/sphinx/bin/all_update.sh
#실행 테스트
]$ /etc/sphinx/bin/all_update.sh
[부분 인덱스]
]$ vi /etc/sphinx/bin/partition_update.sh
#!/bin/bash
# zip_code
indexer sph_zip_code_delta --rotate
indexer --merge sph_zip_code sph_zip_code_delta --rotate
스크립트 파일 생성후 아래와 같이 부분 인덱스 실행 명령어 기술하고 저장합니다.
직접 crontab 등록해도 되는데 왜 스크립트 파일로 만들어서 귀찮게 하는걸까요?
이유는 인덱싱 해야 할 테이블이 zip_code 하나만 있는게 아니기 때문입니다.
게시물 테이블, 상품 등록 테이블 등 다수개의 테이블을 각각 sphinx.conf에 main, delta 쌍으로 등록해야 하고 각각을 indexer로 등록해야 하는데 crontab에는 해당 스크립트 파일 하나만 걸어주고 추가되는 인덱스들은 해당 스크립트에 명령어를 추가 하려고 합니다.
# 권한 부여
]$ chmod 755 /etc/sphinx/bin/partition_update.sh
#실행 테스트
]$ /etc/sphinx/bin/partition_update.sh
[crontab]
]$ vi /etc/crontab
# [스핑크스] 전체 인덱스 (매일 1시 실행)
0 1 * * * root /etc/sphinx/bin/all_update.sh
# [스핑크스] 부분 인덱스 (매일 6시~23시 중 5분마다 실행)
*/5 6-23* * * * root /etc/sphinx/bin/partition_update.sh
마무리
제가 드리고 싶은 이야기는 다 한 것 같습니다.
사이트내의 간략한 통합검색 같은 기능은 가벼고 쉬운 스핑크스로도 충분하다고 생각이 듭니다.
사용하다가 부족하다 싶으면 다른 검색엔진 들고 찾아뵙도록 하겠습니다.
다들 꼭 성공하세요~
[참고]
https://sacstory.tistory.com/entry/Debain-%EA%B2%80%EC%83%89-%EC%97%94%EC%A7%84-Sphinx-%ED%95%9C%EA%B8%80-%EC%84%A4%EC%A0%95
http://sphinxsearch.com/
http://sphinxsearch.com/docs/manual-2.2.11.html#extended-syntax
본 글은 나의 다른 블로그(폐쇄예정) 에서 작성한 글을 이관한 포스팅입니다. (2018년 12월 6일 작성)
'개발 > MariaDB' 카테고리의 다른 글
MySQL innoDB는 어떻게 생겼나요? [InnoDB Architecture] (0) | 2022.10.26 |
---|---|
[MySQL] MySQL 리플리케이션 UUID 관련 에러 (0) | 2022.10.25 |
sphinx #3 :: MySQL에서 스핑크스 직접 join하기 (sphinxSE) (0) | 2022.10.25 |
sphinx #2 :: 스핑스크 쿼리 테스트 (sphinxQL + PHP연동) (0) | 2022.10.25 |
Sphinx #1 :: 스핑크스 설치 및 환경설정 (0) | 2022.10.25 |
댓글
이 글 공유하기
다른 글
-
MySQL innoDB는 어떻게 생겼나요? [InnoDB Architecture]
MySQL innoDB는 어떻게 생겼나요? [InnoDB Architecture]
2022.10.26 -
[MySQL] MySQL 리플리케이션 UUID 관련 에러
[MySQL] MySQL 리플리케이션 UUID 관련 에러
2022.10.25 -
sphinx #3 :: MySQL에서 스핑크스 직접 join하기 (sphinxSE)
sphinx #3 :: MySQL에서 스핑크스 직접 join하기 (sphinxSE)
2022.10.25 -
sphinx #2 :: 스핑스크 쿼리 테스트 (sphinxQL + PHP연동)
sphinx #2 :: 스핑스크 쿼리 테스트 (sphinxQL + PHP연동)
2022.10.25