데이터베이스에서 매우 큰 문자열 / 레코드 목록을 빠르게 검색하는 방법


32

다음과 같은 문제가 있습니다. 2 백만 개 이상의 레코드가 포함 된 데이터베이스가 있습니다. 각 레코드에는 문자열 필드 X가 있으며 필드 X에 특정 문자열이 포함 된 레코드 목록을 표시하려고합니다. 각 레코드의 크기는 약 500 바이트입니다.

좀 더 구체적으로 : 응용 프로그램의 GUI에는 문자열을 입력 할 수있는 텍스트 필드가 있습니다. 텍스트 필드 위에 텍스트 필드의 문자열과 일치하는 (첫 번째 N, 예를 들어 100) 레코드를 표시하는 테이블이 있습니다. 텍스트 필드에 문자를 입력하거나 삭제할 때 테이블 내용을 즉시 업데이트해야합니다.

적절한 인덱스 구조 및 / 또는 캐싱을 사용 하여이 작업을 수행하는 효율적인 방법이 있는지 궁금합니다. 위에서 설명한 것처럼 쿼리와 일치하는 첫 번째 N 항목 만 표시하고 싶습니다. 따라서 N의 크기가 작 으면 데이터베이스에서 일치하는 항목을로드하는 데 큰 문제가되지 않습니다. 또한 주 메모리에 항목을 캐시하면 검색 속도가 빨라질 수 있습니다.

주요 문제는 패턴 문자열을 고려하여 일치하는 항목을 빨리 찾는 방법입니다. 일부 DBMS 기능에 의존 할 수 있습니까? 아니면 인 메모리 인덱스를 직접 만들어야합니까? 어떤 아이디어?

편집하다

첫 번째 실험을 진행했습니다. 레코드를 다른 텍스트 파일로 분할하고 (파일 당 최대 200 개의 레코드) 파일을 다른 디렉토리에 넣었습니다 (한 데이터 필드의 내용을 사용하여 디렉토리 트리를 결정했습니다). 약 40000 개의 디렉토리에 약 50000 개의 파일이 있습니다. 그런 다음 Lucene을 실행하여 파일을 색인화했습니다. Lucene 데모 프로그램으로 문자열을 검색하는 것은 매우 빠릅니다. 분할 및 인덱싱에는 몇 분이 걸렸습니다. 쿼리하려는 정적 데이터 세트이기 때문에 이것은 전적으로 허용됩니다.

다음 단계는 Lucene을 기본 프로그램에 통합하고 Lucene이 리턴 한 적중을 사용하여 관련 레코드를 기본 메모리에로드하는 것입니다.


2
2 백만 레코드 * 500 바이트 = 1GB의 데이터 그것은 검색해야 할 많은 양 의 데이터입니다. 어떤 방식 으로든 X의 각 값이 고유 할 가능성이 있습니까, 아니면 X의 동일한 값을 가진 많은 레코드가 있습니까?

1
그것은 빠른 검색을 위해 캐시에 메모리에 저장하려고 시도 하는 많은 데이터 일 것입니다. 이는 사용자 세션 당 1GB 이상과 동일합니다.
maple_shaft

내 이전 의견은 웹 응용 프로그램을 가정합니다. 이것은 웹 애플리케이션입니까?
maple_shaft

데스크톱 응용 프로그램입니다. 레코드의 값이 반드시 고유하지는 않습니다. 또한 정확히 일치하지 않는 하위 문자열을 검색하고 있습니다.
Giorgio

@maple_shaft : 최근에 액세스 한 레코드 만 캐시합니다. 쿼리 문자열을 변경했는데 레코드가 여전히 일치하면 여전히 캐시에 있습니다.
Giorgio

답변:


20

DB에 데이터를 저장하는 대신이를 일련의 문서 (텍스트 파일)로 유지하고 링크 (경로 / URL 등)를 DB에 유지할 수 있습니다.

이는 디자인에 의한 SQL 쿼리가 하위 문자열 검색과 검색 모두에서 매우 느리기 때문에 필수적입니다.

이제 문제는 문자열 집합이 포함 된 텍스트 파일을 검색해야하는 것으로 공식화되었습니다. 여기에는 두 가지 가능성이 있습니다.

  1. 하위 문자열 일치 텍스트 얼룩이 단일 스팅 또는 단어 (공백 없음)이고 임의의 하위 문자열을 검색해야하는 경우. 이러한 경우 일치하는 최상의 파일을 찾기 위해 모든 파일을 구문 분석해야합니다. 하나는 Boyer Moor 알고리즘과 같은 알고리즘을 사용합니다. 만나다 내용은. grep은 grep과 비슷합니다. grep은 비슷한 것을 내부에서 사용하기 때문입니다. 그러나 귀국하기 전에 여전히 최소 100 + grep (최악의 경우 2 백만)을 만들 수 있습니다.

  2. 인덱스 검색. 여기서 텍스트에 단어 세트가 포함되어 있고 검색이 고정 단어 길이로 제한되어 있다고 가정합니다. 이 경우 문서는 가능한 모든 단어에 대해 색인됩니다. 이것을 "전체 텍스트 검색"이라고합니다. 이를 수행하기위한 많은 알고리즘과 직접 사용할 수있는 오픈 소스 프로젝트가 있습니다. 이들 중 다수는 아래와 같이 와일드 카드 검색, 근사 검색 등을 지원
    합니다. Apache Lucene : http://lucene.apache.org/java/docs/index.html
    b. OpenFTS : http://openfts.sourceforge.net/
    c. 스핑크스 http://sphinxsearch.com/

쿼리로 "고정 단어"가 필요한 경우, 두 번째 방법은 매우 빠르고 효과적입니다.


2
이것은 흥미로운 개념이지만 개발자가 데이터베이스 엔진보다 1GB의 텍스트 데이터를 더 빠르고 효율적으로 쉽게 검색 할 수 없을 것 같습니다. 당신보다 훨씬 똑똑한 사람들과 나는 쿼리 최적화 프로그램을 통해 그 일을하기 위해 노력해 왔으며 어떻게 든 더 효율적으로 할 수 있다고 생각하는 것은 순진합니다.
maple_shaft

4
@maple_shaft 내가 제공 한 예제는 RDBMS 데이터베이스 엔진이 아닙니다. 전화를 걸려면 "검색 엔진"과 비슷합니다. 인덱스 (또는 해시 테이블)에서 목록을 선택하는 것과 쿼리가 실행될 때마다 1GB의 데이터를 다시 검색하는 것 사이에는 큰 개념 차이가 있습니다. 그래서 내가 제안하는 것은 사소한 조정이 아닙니다.
Dipan Mehta

이것은 흥미로운 아이디어처럼 보이지만 어떻게 작동하는지 궁금합니다. 크기가 각각 약 0.5KB 인 2 만 개가 넘는 파일이 있습니다. 또는 파일 당 두 개 이상의 레코드를 제안 하시겠습니까? 데이터베이스와의 차이점은 무엇입니까?
Giorgio

이것이 SQL 전체 텍스트 인덱스보다 반드시 더 나은 성능을 발휘할 것이라고 확신하지는 않습니다.
Kirk Broadhurst

@Giorgio-예, 전체 텍스트 검색 엔진이 작동하는 방식입니다. 여기서 중요한 차이점은 미리 색인 된 페이지 대 메모리 검색 (쿼리가 올 때마다 다시)입니다.
Dipan Mehta

21

찾고있는 기술은 전체 텍스트 인덱싱입니다. 대부분의 RDBMS에는 여기에서 작동하는 일종의 내장 기능이 있거나, 더 좋아지고 메모리에서 실행하려는 경우 Lucene과 같은 것을 사용할 수 있습니다.


1
제 생각에는 RDBMS의 전체 텍스트 옵션은 "구조화되지 않은 관련되지 않은 데이터 더미에서 검색"을 위해 설계되지 않은 작업을 수행하는 해결 방법입니다. 검색 엔진을 구축하는 경우 RDBMS를 사용하지 않습니다. 작은 데이터 세트에서는 작동하지만 모든 종류의 스케일링에는 영향을 미치지 않습니다. 구조화되지 않은 데이터 더미를 검색하는 것은 쉬운 일이 아니므로 망치를 사용하지 마십시오. 작업에 적합한 도구를 사용하십시오.
Pieter B

8

당신은 트라이 를 고려 했습니까 ? 기본적으로 공통 접두사를 사용하여 트리를 작성하므로 동일한 문자로 시작하는 모든 단어는 동일한 노드의 자식입니다. 하위 문자열에서 일치하는 것을 지원하려면 일종의 순열 인덱스 를 생성하고 그로부터 trie를 작성해야합니다. 그래도 스토리지 요구 사항이 사라질 수 있습니다.


1
예! 나는 나무 구조에 대해 생각하고 있었고 나에게 적합한 비슷한 것이 있다는 것을 기억했지만, 결코 사용하지 않았기 때문에 trie를 기억하지 못했습니다. 스토리지 요구 사항과 관련하여 : 20000 적중으로 테이블을 채우는 것은 의미가 없으므로 첫 번째 N 항목 (예 : N = 100) 만 검색해야합니다. 따라서 trie의 각 노드는 최대 N 개의 항목을 가리 킵니다. 또한 빠른 액세스가 필요하지만 데이터가 한 번만로드되기 때문에 빠른 업데이트가 필요하지 않습니다. 순열 인덱스에 대한 세가지 아이디어는 실제로 효과가 있습니다!
Giorgio

1
좋은 답변을하지만,주의 등의 트라이은 일치에 좋은 곳입니다 시작 하여 단어를하지만 빨리 얻을 것이다 복잡하고 어떤 문자열을 일치 ... 경우 매우 큰
커크 Broadhurst

첫 번째 실험으로, 검색 해야하는 문자열에 나타나는 모든 하위 문자열 세트를 작성하려고 시도했지만 올바르게 이해하면 trie의 경로에 해당합니다. 길이 6의 하위 문자열에서 메모리 부족 예외 (JVM의 경우 256M 힙 포함)가 발생했습니다.
Giorgio

5

Wyatt Barnett의 답변에 추가하여 적절한 열에 전체 텍스트 인덱싱을 사용하는 RDBMS 솔루션이 작동하지만 이전에 가져온 레코드의 로컬 캐시를 사용하려면 이러한 캐시 된 레코드를 활용할 계획이 필요합니다 당신의 이점에.

한 가지 옵션은 쿼리에서 명시 적으로 검색하지 않으려는 이러한 레코드의 고유 식별자를 수집하여 가능한 경우 a NOT IN또는 a에 포함시키는 것 NOT EXISTS입니다.

그러나주의 NOT IN하거나 사용 NOT EXISTS하는 것이 저렴하지는 않으며 사용중인 데이터베이스 엔진에 따라 쿼리 성능 또는 쿼리 계획에 부정적인 영향을 줄 수 있습니다. 최종 쿼리에서 Explain Plan을 실행하여 영향을받는 열의 모든 인덱스가 사용되도록하십시오.

또한 두 가지 방법 중 성능 비교를 수행하여 어느 것이 더 빠른지 아프지 않습니다. 로컬 캐시를 유지 관리하고 쿼리에서 캐시를 명시 적으로 필터링하면 모든 레코드를 가져 오는 미세 조정 된 쿼리보다 성능이 저하 될 수 있습니다.


maple_shaft 및 @Wyatt Barnett : 제안 해 주셔서 감사합니다. 나는 약간의 독서를하고 다른 해결책을 시도해야 할 것입니다. 모든 데이터베이스가 전체 인덱싱을 지원하는 것은 아니며 MySQL (현재 사용중인)은 dev.mysql.com/doc/refman/5.5/en/fulltext-search.html을 지원 합니다. 테스트를 해보고 여기에보고하겠습니다.
Giorgio

2

당신이 그것을 놓친 경우를 대비하여. DB 내 지원 텍스트 검색 대신 데이터베이스에 Lucene을 사용하는 경우 DB를 수정할 때 매우주의해야합니다. DB와 외부 리소스 (Lucene)를 모두 변경해야 할 때 원 자성을 가질 수있는 방법은 무엇입니까? 그렇습니다, 그러나 많은 일이있을 것입니다.

간단히 말해 Lucene을 데이터 스키마에 넣으면 DB 트랜잭션 지원이 손실됩니다.


1
언급 된 문제는 RDMS에 적합하지 않은 것 같습니다.
Pieter B

1

스핑크스를 고려 했습니까? http://sphinxsearch.com 타사 도구를 사용할 수 있다면 이것이 달성하려는 목표에 이상적입니다. 개인적으로 사용한 RDBMS보다 전체 텍스트 검색에서 훨씬 더 효율적입니다.


3
그리고 다운 투표는 무엇입니까?
twigg

1

어떤 답변도 Apache Lucene 및 기타 솔루션과 유사한 모든 솔루션의 기초가되는 기술인 "inverted index" 라는 용어를 제시하지 않은 것은 다소 이상합니다 .

반전 된 색인은 단어에서 문서로의 매핑 ( "레코드 수준 반전 된 색인") 또는 문서 내의 정확한 단어 위치 ( "워드 수준의 반전 된 색인")입니다.

AND 및 OR 논리 연산은 구현하기가 쉽지 않습니다. 정확한 단어 위치가 있으면 인접한 단어를 찾아 구문 검색을 수행 할 수 있습니다.

따라서 (단어, 파일, 위치) 튜플을 포함하는 색인에 대해 생각하십시오. 예를 들어 ( "inverted", "foo.txt", 123)가있는 경우 ( "index", "foo.txt", 124)가 "inverted index"라는 구절을 검색하기위한 인덱스의 일부인지 확인하면됩니다. .

전체 텍스트 검색 엔진을 처음부터 다시 구현하는 것은 좋지 않지만 Apache Lucene과 같은 기술의 작동 방식을 아는 것이 유용합니다.

따라서 역 인덱스가 어떻게 작동하는지 배우고 Apache Lucene과 같은 인덱스를 사용하는 기술을 선택하는 것이 좋습니다. 그런 다음에는 수행 할 수있는 작업과 수행 할 수없는 작업에 대해 확실하게 이해해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.