벡터 검색 개요 - Amazon MemoryDB

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

벡터 검색 개요

벡터 검색은 인덱스 생성, 유지 관리 및 사용을 기반으로 합니다. 각 벡터 검색 작업은 단일 인덱스를 지정하며 해당 인덱스로만 제한됩니다. 즉, 한 인덱스에 대한 작업은 다른 인덱스에 대한 작업의 영향을 받지 않습니다. 인덱스 생성 및 삭제 작업을 제외하고 언제든지 모든 인덱스에 대해 원하는 수의 작업을 실행할 수 있습니다. 즉, 클러스터 수준에서는 여러 인덱스에 대한 여러 작업이 동시에 진행될 수 있습니다.

개별 인덱스는 키, 함수 등 다른 Redis OSS 네임스페이스와는 별개인 고유한 네임스페이스에 존재하는 명명된 객체입니다. 각 인덱스는 열과 행이라는 두 가지 차원으로 구성된다는 점에서 기존 데이터베이스 테이블과 개념적으로 유사합니다. 테이블의 각 행은 Redis OSS 키에 해당합니다. 인덱스의 각 열은 해당 키의 멤버 또는 일부에 해당합니다. 이 문서 내에서 키, 행 및 레코드라는 용어는 동일한 의미로 통용됩니다. 마찬가지로 열, 필드, 경로 및 멤버라는 용어는 본질적으로 동일한 의미로 통용됩니다.

인덱싱된 데이터를 추가, 삭제 또는 수정하기 위한 특별한 명령은 없습니다. 대신 인덱스에 있는 키를 수정하는 기존 HASH 또는 JSON 명령도 인덱스를 자동으로 업데이트합니다.

인덱스 및 레디 스 OSS 키스페이스

인덱스는 Redis OSS 키스페이스의 하위 집합에서 구성되고 유지 관리됩니다. 여러 인덱스는 제한 없이 Redis OSS 키스페이스의 분리되거나 겹치는 하위 집합을 선택할 수 있습니다. 각 인덱스의 키스페이스는 인덱스 생성 시 제공되는 키 접두사 목록에 의해 정의됩니다. 접두사 목록은 선택 사항이며 생략하면 전체 Redis OSS 키스페이스가 해당 인덱스의 일부가 됩니다. 또한 인덱스는 유형이 일치하는 키만 포함하도록 입력됩니다. 현재는 JSON 및 HASH 인덱스만 지원됩니다. HASH 인덱스는 접두사 목록에 포함된 HASH 키만 인덱싱하고, 마찬가지로 JSON 인덱스는 접두사 목록에 포함된 JSON 키만 인덱싱합니다. 인덱스의 키스페이스 접두사 목록 내에서 지정된 유형이 없는 키는 무시되며 검색 작업에 영향을 주지 않습니다.

HASH 또는 JSON 명령으로 인덱스의 키스페이스 내에 있는 키를 수정하면 해당 인덱스가 업데이트됩니다. 이 프로세스에는 각 인덱스에 대해 선언된 필드를 추출하고 새 값으로 인덱스를 업데이트하는 작업이 포함됩니다. 업데이트 프로세스는 백그라운드 스레드에서 수행되므로 인덱스가 최종적으로 해당 키스페이스 콘텐츠와 일치해야 합니다. 따라서 키를 삽입하거나 업데이트해도 당장은 검색 결과에 표시되지 않습니다. 시스템 부하가 심하거나 데이터가 심하게 변경되는 기간에는 가시성 지연이 더 길어질 수 있습니다.

인덱스 생성은 다단계 프로세스입니다. 첫 번째 단계는 인덱스를 정의하는 FT.CREATE 명령을 실행하는 것입니다. 생성을 성공적으로 실행하면 두 번째 단계인 채우기가 자동으로 시작됩니다. 백필 프로세스는 백그라운드 스레드에서 실행되며 Redis OSS 키 스페이스를 스캔하여 새 인덱스의 접두사 목록 내에 있는 키를 찾습니다. 발견된 각 키는 인덱스에 추가됩니다. 결국 전체 키스페이스가 스캔되어 인덱스 생성 프로세스가 완료됩니다. 채우기 프로세스가 실행되는 동안에는 제한 없이 인덱스 키를 변경할 수 있으며 모든 키가 제대로 인덱싱될 때까지 인덱스 채우기 프로세스가 완료되지 않습니다. 인덱스를 채우는 동안 시도한 쿼리 작업은 허용되지 않으며 오류가 발생하여 종료됩니다. 채우기 프로세스의 완료 여부는 해당 인덱스에 대한 FT.INFO 명령 출력('backfill_status')에서 확인할 수 있습니다.

인덱스 필드 유형

인덱스의 각 필드(열)에는 인덱스 생성 시 선언되는 특정 유형 및 키 내의 위치가 표시됩니다. HASH 키의 경우 위치는 HASH 내의 필드 이름입니다. JSON 키의 경우 위치는 JSON 경로 설명입니다. 키가 수정되면 선언된 필드와 관련된 데이터가 추출되고 선언된 유형으로 변환되어 인덱스에 저장됩니다. 데이터가 누락되었거나 선언된 유형으로 성공적으로 변환할 수 없는 경우 해당 필드는 인덱스에서 제외됩니다. 필드에는 다음 설명과 같이 네 가지 유형이 있습니다.

  • 숫자 필드에는 단일 숫자가 포함됩니다. JSON 필드의 경우 JSON 번호의 숫자 규칙을 따라야 합니다. HASH의 경우 필드에 고정 또는 부동 소수점 숫자의 표준 형식으로 작성된 ASCII 텍스트가 포함되어야 합니다. 키 내 표시 형식에 관계없이 이 필드는 64비트 부동 소수점 숫자로 변환되어 인덱스 내에 저장됩니다. 숫자 필드는 범위 검색 연산자와 함께 사용할 수 있습니다. 기본 숫자는 정밀도 제한에 따라 부동 소수점으로 저장되므로 부동 소수점 숫자 비교에 대한 일반적인 규칙이 적용됩니다.

  • 태그 필드에는 단일 UTF-8 문자열로 코딩된 0개 이상의 태그 값이 포함됩니다. 문자열은 선행 및 후행 공백이 제거된 구분 문자(기본값은 쉼표이지만 재정의할 수 있음)를 사용하여 태그 값으로 구문 분석됩니다. 단일 태그 필드에 원하는 수의 태그 값을 포함할 수 있습니다. 태그 필드를 사용하여 대소문자를 구분하거나 구분하지 않는 비교를 통해 태그 값이 동일한 쿼리를 필터링할 수 있습니다.

  • 텍스트 필드에는 UTF-8 규격을 준수하지 않아도 되는 수많은 바이트가 포함됩니다. 텍스트 필드를 사용하여 쿼리 결과를 애플리케이션에 적합한 값으로 장식할 수 있습니다. 예를 들어 URL이나 문서 내용 등이 가능합니다.

  • 벡터 필드에는 임베딩이라고도 하는 숫자 벡터가 포함됩니다. 벡터 필드는 지정된 알고리즘과 거리 측정법을 사용하여 크기가 고정된 벡터의 K-nearest neighbor(KNN) 검색을 지원합니다. HASH 인덱스의 경우 필드에 바이너리 형식(리틀 엔디안 IEEE 754)으로 인코딩된 전체 벡터가 포함되어야 합니다. JSON 키의 경우 경로는 숫자로 채워진 올바른 크기의 배열을 참조해야 합니다. JSON 배열을 벡터 필드로 사용하는 경우 JSON 키 내 배열의 내부 표현이 선택한 알고리즘에서 요구하는 형식으로 변환되므로 메모리 사용량과 정밀도가 줄어듭니다. 이후에 JSON 명령을 사용하여 읽기 작업을 수행하면 낮아진 정밀도 값을 출력합니다.

벡터 인덱스 알고리즘

다음과 같은 두 개의 벡터 인덱스 알고리즘이 제공됩니다.

  • FLAT - FLAT 알고리즘은 인덱스의 각 벡터를 무차별 대입으로 선형 처리하여 거리 계산의 정밀도 범위 내에서 정확한 답을 산출합니다. 인덱스의 선형 처리로 인해 큰 인덱스의 경우 이 알고리즘의 실행 시간이 매우 길어질 수 있습니다.

  • HNSW (Hierarchical Navigable Small Worlds) — HNSW 알고리즘은 실행 시간을 크게 줄이는 대신 정답의 근사치를 제공하는 대안입니다. 알고리즘은 세 개의 파라미터 M, EF_CONSTRUCTION, EF_RUNTIME에 의해 제어됩니다. 처음 두 파라미터는 인덱스 생성 시 지정되며 변경할 수 없습니다. 이 EF_RUNTIME 파라미터는 인덱스 생성 시 지정되는 기본값을 갖지만 이후에 개별 쿼리 작업에서 재정의할 수 있습니다. 이 세 파라미터는 상호 작용하여 수집 및 쿼리 작업 중에 메모리와 CPU 사용량의 균형을 맞추고 정확한 KNN 검색의 근사치 품질(재현율)을 제어합니다.

벡터 검색 알고리즘(FLAT 및 HNSW) 모두 선택적 INITIAL_CAP 파라미터를 지원합니다. 이 파라미터를 지정하면 인덱스에 메모리를 사전 할당하여 메모리 관리 오버헤드를 줄이고 벡터 수집 비율을 높입니다.

HNSW와 같은 벡터 검색 알고리즘은 이전에 삽입한 벡터의 삭제 또는 덮어쓰기를 효율적으로 처리하지 못할 수 있습니다. 이러한 연산을 사용하면 인덱스 메모리가 과도하게 소모되거나 재현율이 저하될 수 있습니다. 인덱스를 다시 지정하는 것은 최적의 메모리 사용량 또는 재현율을 복원하기 위한 방법 중 하나입니다.

벡터 검색 쿼리 표현식

FT.SEARCHFT.AGGREGATE 명령에는 쿼리 표현식이 필요합니다. 이 표현식은 하나 이상의 연산자로 구성된 단일 문자열 파라미터입니다. 각 연산자는 인덱스의 한 필드를 사용하여 인덱스에 있는 키의 하위 집합을 식별합니다. 부울 컴바이너와 괄호로 여러 연산자를 결합하여 수집된 키 세트(또는 결과 집합)를 더욱 향상시키거나 제한할 수 있습니다.

와일드카드

와일드카드 연산자인 별표('*')는 인덱스의 모든 키와 일치합니다.

숫자 범위

숫자 범위 연산자의 구문은 다음과 같습니다.

<range-search> ::= '@' <numeric-field-name> ':' '[' <bound> <bound> ']' <bound> ::= <number> | '(' <number> <number> ::= <integer> | <fixed-point> | <floating-point> | 'Inf' | '-Inf' | '+Inf'

< >는 선언된 유형 필드여야 numeric-field-name 합니다. NUMERIC 기본적으로 경계값도 검색 범위에 포함되지만 앞에 여는 괄호['(']를 사용하여 경계값이 검색 범위에서 제외되도록 만들 수 있습니다. 범위 검색은 Inf, +Inf 또는 -Inf를 경계값으로 사용하여 단일 관계형 비교(<, <=, >, >=)로 변환될 수 있습니다. 지정된 숫자 형식(정수, 고정 소수점, 부동 소수점, 무한대)에 관계없이 숫자를 64비트 부동 소수점으로 변환하여 비교를 수행하므로 정밀도가 낮아집니다.

@numeric-field:[0 10] // 0 <= <value> <= 10 @numeric-field:[(0 10] // 0 < <value> <= 10 @numeric-field:[0 (10] // 0 <= <value> < 10 @numeric-field:[(0 (10] // 0 < <value> < 10 @numeric-field:[1.5 (Inf] // 1.5 <= value

태그 비교

태그 비교 연산자의 구문은 다음과 같습니다.

<tag-search> ::= '@' <tag-field-name> ':' '{' <tag> [ '|' <tag> ]* '}'

연산자의 태그 중 하나라도 레코드 태그 필드에 있는 태그와 일치하는 경우 해당 레코드가 결과 집합에 포함됩니다. <tag-field-name>에서 디자인하는 필드는 TAG 유형으로 선언된 인덱스의 필드여야 합니다. 태그 비교의 예는 다음과 같습니다.

@tag-field:{ atag } @tag-field: { tag1 | tag2 }

부울 조합

부울 논리 and/or를 사용하여 숫자 연산자 또는 태그 연산자의 결과 집합을 결합할 수 있습니다. 괄호를 사용하여 연산자를 그룹화하거나 평가 순서를 변경할 수 있습니다. 부울 논리 연산자의 구문은 다음과 같습니다.

<expression> ::= <phrase> | <phrase> '|' <expression> | '(' <expression> ')' <phrase> ::= <term> | <term> <phrase> <term> ::= <range-search> | <tag-search> | '*'

여러 용어가 하나의 구문으로 결합될 때 ‘and’ 연산이 수행됩니다. 여러 구문이 파이프(‘|’)로 결합될 때 'or' 연산이 수행됩니다.

벡터 인덱스는 가장 가까운 이웃과 범위라는 두 가지 검색 방법을 지원합니다. 최근접이웃 검색은 인덱스에서 제공된 (참조) 벡터와 가장 가까운 벡터 중 K를 찾습니다. 이 벡터는 흔히 'K' 개의 최근접이웃을 뜻하는 KNN이라고 합니다. KNN 검색 구문은 다음과 같습니다.

<vector-knn-search> ::= <expression> '=>[KNN' <k> '@' <vector-field-name> '$' <parameter-name> <modifiers> ']' <modifiers> ::= [ 'EF_RUNTIME' <integer> ] [ 'AS' <distance-field-name>]

벡터 KNN 검색은 와일드카드, 범위 검색, 태그 검색 및/또는 이러한 연산자의 부울 조합 등 위에 정의된 연산자의 모든 조합을 만족하는 벡터에만 적용됩니다. <expression>

  • <k>는 반환되는 가장 가까운 이웃 벡터의 수를 지정하는 정수입니다.

  • <vector-field-name>은 선언된 VECTOR 유형의 필드를 지정해야 합니다.

  • <parameter-name> 필드는 FT.SEARCH 또는 FT.AGGREGATE 명령의 PARAM 테이블 항목 중 하나를 지정합니다. 이 파라미터는 거리 계산을 위한 참조 벡터 값입니다. 벡터 값은 리틀 엔디안 IEEE 754 바이너리 형식의 PARAM 값으로 인코딩됨(HASH 벡터 필드와 동일하게 인코딩됨)

  • HNSW 유형의 벡터 인덱스의 경우 선택적 EF_RUNTIME절을 사용하여 인덱스 생성 시 설정된 EF_RUNTIME 파라미터의 기본값을 재정의할 수 있습니다.

  • 선택적 <distance-field-name>은 결과 집합에 참조 벡터와 찾은 키 사이의 계산된 거리를 포함하는 필드 이름을 제공합니다.

범위 검색은 참조 벡터로부터 지정된 거리 (반경) 내에 있는 모든 벡터를 찾습니다. 범위 검색 구문은 다음과 같습니다.

<vector-range-search> ::= ‘@’ <vector-field-name> ‘:’ ‘[’ ‘VECTOR_RANGE’ ( <radius> | ‘$’ <radius-parameter> ) $<reference-vector-parameter> ‘]’ [ ‘=’ ‘>’ ‘{’ <modifiers> ‘}’ ] <modifiers> ::= <modifier> | <modifiers>, <modifier> <modifer> ::= [ ‘$yield_distance_as’ ‘:’ <distance-field-name> ] [ ‘$epsilon’ ‘:’ <epsilon-value> ]

위치:

  • <vector-field-name>검색할 벡터 필드의 이름입니다.

  • <radius> or $<radius-parameter>검색을 위한 수치적 거리 제한입니다.

  • $<reference-vector-parameter> 참조 벡터가 포함된 매개변수의 이름입니다. 벡터 값은 리틀 엔디안 IEEE 754 바이너리 형식 (해시 벡터 필드와 동일한 인코딩) 의 PARAM 값으로 인코딩됩니다.

  • 선택 항목은 참조 <distance-field-name> 벡터와 각 키 사이의 계산된 거리를 포함하는 결과 집합의 필드 이름을 제공합니다.

  • 선택 항목은 검색 작업의 경계를 <epsilon-value> 제어하며, 거리 내의 벡터를 순회하여 후보 <radius> * (1.0 + <epsilon-value>) 결과를 찾습니다. 기본값은 0.01입니다.

INFO 명령

벡터 검색은 Redis OSS INFO 명령을 통계 및 카운터의 몇 가지 추가 섹션으로 보강합니다. SEARCH 섹션 검색을 요청하면 다음 섹션이 모두 검색됩니다.

search_memory 섹션

명칭 설명
search_used_memory_bytes 모든 검색 데이터 구조에서 사용된 메모리 바이트 수
search_used_memory_human 사람이 읽을 수 있는 위의 버전

search_index_stats 섹션

명칭 설명
search_number_of_indexes 생성된 인덱스 수
search_num_fulltext_indexes 모든 인덱스의 벡터가 아닌 필드 수
search_num_vector_indexes 모든 인덱스 내 벡터 필드 수
search_num_hash_indexes HASH 유형 키의 인덱스 수
search_num_json_indexes JSON 유형 키의 인덱스 수
search_total_indexed_keys 모든 인덱스의 총 키 수
search_total_indexed_vectors 모든 인덱스의 총 벡터 수
search_total_indexed_hash_keys 모든 인덱스의 HASH 유형 총 키 수
search_total_indexed_json_keys 모든 인덱스의 JASON 유형 총 키 수
search_total_index_size 모든 인덱스에서 사용하는 바이트
search_total_fulltext_index_size 벡터가 아닌 인덱스 구조에서 사용되는 바이트
search_total_vector_index_size 벡터 인덱스 구조에서 사용되는 바이트
search_max_index_lag_ms 마지막 수집 배치 업데이트 동안의 수집 지연

search_ingestion 섹션

명칭 설명
search_background_indexing_status 수집 상태 NO_ACTIVITY는 유휴 상태를 의미합니다. 다른 값은 키가 수집 중인 키가 있음을 나타냅니다.
search_ingestion_paused 다시 시작하는 경우를 제외하고는 항상 ‘no’여야 합니다.

search_backfill 섹션

참고

이 섹션에 설명된 일부 필드는 채우기가 진행 중일 때만 표시됩니다.

명칭 설명
search_num_active_backfills 현재 채우기 활동 수
search_backfills_paused 메모리가 부족한 경우를 제외하고는 항상 ‘no’여야 합니다.
검색_현재_백필_진행률_백분율 현재 채우기 완료율 (0-100)

search_query 섹션

명칭 설명
search_num_active_queries 현재 진행 중인 FT.SEARCH 명령 및 FT.AGGREGATE 명령 수

벡터 검색 보안

명령 및 데이터 액세스 모두에 대한 Redis OSS ACL (액세스 제어 목록) 보안 메커니즘이 검색 기능을 제어하도록 확장되었습니다. 개별 검색 명령의 ACL 제어가 완벽하게 지원됩니다. 새 ACL 범주 @search가 추가되었으며 많은 기존 범주(@fast, @read, @write 등)가 새 명령을 포함하도록 업데이트되었습니다. 검색 명령은 키 데이터를 수정하지 않습니다. 즉, 쓰기 액세스를 위한 기존 ACL 시스템이 보존됩니다. HASH 및 JSON 작업에 대한 액세스 규칙은 인덱스가 있더라도 수정되지 않습니다. 이러한 명령에는 여전히 일반적인 키 수준 액세스 제어가 적용됩니다.

인덱스가 있는 검색 명령의 액세스도 Redis OSS ACL을 통해 제어됩니다. 액세스 확인은 키별 수준이 아닌 전체 인덱스 수준에서 수행됩니다. 즉, 사용자가 해당 인덱스의 키스페이스 접두사 목록 내에서 가능한 모든 키에 액세스할 수 있는 권한을 가진 경우에만 사용자에게 인덱스 액세스 권한이 부여됩니다. 즉, 인덱스의 실제 콘텐츠는 액세스를 제어하지 않습니다. 그보다는 접두사 목록에 정의된 인덱스의 이론상 내용이 보안 검사에 사용됩니다. 사용자에게 키에 대한 읽기 및/또는 쓰기 액세스는 있지만 해당 키가 포함된 인덱스에는 액세스할 수 없는 상황이 발생하기 쉽습니다. 인덱스를 만들거나 사용할 때는 키스페이스에 대한 읽기 액세스만 필요하며 쓰기 액세스 유무는 고려되지 않습니다.

MemoryDB와 함께 ACL을 사용하는 방법을 자세히 알아보려면 액세스 제어 목록(ACL)을 사용하여 사용자 인증을 참조하세요.