이 문서에서 다루는 주제
- N1QL의 장점은 무엇인가요?
- FTS는 어떻게 되나요?
- 그렇다면 왜 N1QL 내의 FTS일까요?
- 기본 N1QL+FTS 쿼리
- N1QL+FTS 배포
- 구문(들)
- 기능 및 제한 사항
- N1QL+FTS 내부
- 커버된 인덱스 쿼리 대 비커버된 인덱스 쿼리
- N1QL+FTS 쿼리 예제 더 보기
- 다음 단계는 무엇인가요?
1. 카우치베이스의 N1QL
- N1QL은 카우치베이스 서버에 저장된 JSON 데이터를 조작하기 위한 카우치베이스의 SQL 제품입니다.
- N1QL 문을 사용하여 인덱스를 생성, 수정, 삭제하고 JSON 문서에 데이터를 선택, 삽입, 업데이트, 삭제 및 업서트할 수 있습니다.
- N1QL 표현식을 사용하면 집계, 산술, 수집, 비교, 조건부 및 기타 여러 가지 연산을 수행할 수 있습니다.
- 이 모든 작업은 보조 인덱스의 지원을 통해 매우 효율적으로 이루어집니다.
2. 카우치베이스의 FTS
- 카우치베이스의 전체 텍스트 검색 서비스는 자연어 쿼리를 위한 광범위한 기능을 제공하며, 사용자가 카우치베이스 서버에 저장된 JSON 문서의 여러 필드에 걸쳐 텍스트를 검색할 수 있도록 지원합니다.
- 사용자가 구성할 수 있는 언어 인식 검색 및 관련성에 기반한 결과 채점을 지원합니다.
- FTS는 매우 특수하게 설계되어 광범위한 텍스트 검색 워크로드를 매우 효율적으로 처리할 수 있는 빠른 인덱스를 설정합니다.
3. N1QL을 통해 FTS를 지원하는 이유는 무엇인가요?
- N1QL 쿼리는 문자열, 숫자, 배열 등에 대한 검색을 수행할 수 있으며 보조 인덱싱(b-tree 인덱스)을 통해 포인트 조회 및 범위 스캔도 지원하지만, FTS는 기본 반전 인덱스의 지원으로 텍스트 검색(단순 및 복잡한 복합 쿼리)에 대한 성능을 제공합니다.
- 애플리케이션은 단일 API와 언어를 사용하여 두 가지 기능을 모두 활용할 수 있는 기능이 필요합니다.
- 개발의 용이성을 위해 FTS 결과에 집계, 산술 및 기타 SQL 연산을 적용하는 등 복합/복잡한 연산을 지원합니다.
- FTS의 가시성을 확장하세요(SDK, curl 또는 Couchbase의 UI를 통해서만 가능한 것이 아닙니다).

4. N1QL + FTS
Couchbase 6.5는 N1QL과 FTS 간에 제안된 인터페이스를 지원합니다. 사용자는 여전히 다음과 같이 사용 사례를 지원하기 위해 FTS 인덱스를 설정해야 합니다. GSI (글로벌 보조 인덱싱). 이 새로운 인터페이스를 통해 사용자는 N1QL 쿼리 내에서 FTS 쿼리를 원활하게 병합하고 실행할 수 있게 됩니다.
이제 새로운 SEARCH(..) 술어가 N1QL 쿼리 구문의 일부로 지원됩니다. SEARCH(...) 술어가 포함된 N1QL 쿼리가 실행될 때 어떤 일이 일어나는지 내부를 살펴보기 전에 먼저 알아보겠습니다, 여기 는 FTS 인덱스 생성 및 관리 방법에 대한 문서이며 다음은 몇 가지 샘플 쿼리입니다.
예를 들어 일부 여행 문서에 대해 FTS 인덱스가 설정되어 있고 도시 필드에 '샌프란시스코'가 포함된 모든 문서에 대한 FTS 결과(ID만)를 가져오고 싶다고 가정해 보겠습니다.
|
1 2 3 |
선택 메타().id FROM `여행-샘플` as t 어디 검색(t, '도시:"San Francisco"'); |
위에서 볼 수 있듯이 FTS 쿼리 문자열 'city:"San Francisco"'가 N1QL 쿼리 내에 포함되어 있습니다. 또는 N1QL 쿼리는 다음과 같은 FTS 쿼리 개체도 지원합니다.
|
1 2 3 4 |
선택 메타().id FROM `여행-샘플` as t 어디 검색(t, {"일치_문구": "San Francisco", "필드": "도시"}) LIMIT 10; |
위의 예에서는 FTS 결과 집합을 10으로 제한합니다.
또는 FTS 검색 요청 개체도 ...
|
1 2 3 |
선택 메타().id FROM `여행-샘플` as t 어디 검색(t, {"쿼리": {"일치_문구": "San Francisco", "필드": "도시"}, "limit": 10}); |
위의 예에서도 결과 집합을 10개로 제한하지만 FTS는 이를 적용합니다.
오프셋/제한 필터는 N1QL 쿼리 구문 또는 FTS 검색 요청 개체 내에서 설정할 수 있습니다. 이러한 매개변수가 FTS 검색 요청 내에 설정되어 있으면 FTS는 요청된 수의 결과만 스트리밍합니다. N1QL 매개변수는 FTS가 전송한 모든 결과에 적용됩니다. 이러한 설정이 FTS 개체 내에 설정되어 있지 않고 N1QL 쿼리에서 설정되어 있는 경우 FTS는 N1QL이 필요한 모든 결과를 수신할 때까지 모든 결과를 N1QL로 스트리밍합니다.
또한 지난 세 가지 예제에서와 마찬가지로 선택할 FTS 인덱스의 이름을 명시적으로 지정할 필요가 없습니다. N1QL은 사용 가능한 인덱스 중에서 FTS 쿼리를 실행하기에 가장 적합한 인덱스를 결정합니다. N1QL이 특정 인덱스(예: "travel"이라는 이름의 인덱스)를 사용하도록 하려면 다음과 같이 하세요.
|
1 2 3 |
선택 메타().id FROM `여행-샘플` as t 어디 검색(t, {"일치_문구": "San Francisco", "필드": "도시"}, {"색인": "여행"}); |
위의 모든 예제 쿼리의 경우 결과는 스트리밍되며 관련성(점수 - 기본 FTS 동작)에 따라 정렬되지 않습니다. 정렬은 검색 요청에 명시적으로 명시하거나 N1QL의 주문 기준 절을 추가할 수 있습니다. 결과 페이지 매김은 검색 요청 내에 명시적으로 명시하거나 N1QL의 오프셋 그리고 LIMIT 조항.
5. N1QL + FTS 배포
- SEARCH(..) 기능으로 N1QL 쿼리를 허용하려면 카우치베이스 클러스터에 검색 서비스를 실행하는 노드 1개와 쿼리 서비스를 실행하는 노드 1개 이상이 있어야 합니다(이 두 서비스를 동일한 노드에서 구성할 수도 있음).
- FTS 인덱스는 사용자가 검색하고자 하는 필요한 콘텐츠의 색인을 설정하기 위해 설정해야 합니다.
- N1QL이 쿼리를 실행할 수 있는 FTS 인덱스를 찾지 못한 경우, 쿼리를 처리할 수 있는 GSI 인덱스를 검색합니다. 이 경우, 검색(...) 술어는 얻은 중간 결과에 적용됩니다. 이 방법은 효과가 있지만 SEARCH(...) 평가 비용이 많이 들 수 있으므로 권장되는 접근 방식은 아닙니다.
- SEARCH(..)를 사용하는 N1QL 쿼리는 쿼리 워크벤치, curl, SDK 또는 couchbase가 제공하는 명령줄 인터페이스에서 실행할 수 있습니다.
5.1 검색 구문
다음은 SEARCH(, , [옵션]) 함수에서 지원되는 기능입니다.

5.2 기능 및 제한 사항
- FTS 검색 요청이 제공하는 모든 기능은 N1QL 쿼리에서 지원됩니다.
- 여기 다음은 SEARCH(...) 함수 내의 "쿼리" 섹션에 무엇을 넣어야 하는지에 대한 몇 가지 주요 사항입니다.
- 다중 유형 매핑을 지원하는 FTS 인덱스는 결과 집합에 오탐이 들어가지 않도록 N1QL+FTS 인터페이스의 첫 번째 릴리스에서 허용되지 않습니다.
내부 구현
내부적으로 N1QL+FTS 인터페이스는 검색(..) 술어가 있는 쿼리에 대한 준비 및 실행 단계에서 N1QL 서비스가 호출하는 4개의 API를 지원합니다.

위의 API를 좀 더 자세히 설명하기 전에 인터페이스 내에서 지원되는 작업의 흐름도는 다음과 같습니다.

6.1 사가블
이 FTS 인덱스 API는 인덱스가 오탐을 반환하지 않고 쿼리 요청을 처리할 수 있는지 여부를 결정하는 데 사용됩니다. 첫 번째 릴리즈에서는 모든 쿼리 필드가 그 안에 인덱싱되어 있거나 인덱스 정의 내에 요청된 모든 필드를 처리할 수 있는 동적 매핑이 있는 경우에만 인덱스가 선택됩니다. 주어진 쿼리에 대해 여러 인덱스가 색인 가능한 경우, 성능상의 이유로 색인 가능 절을 만족하는 색인된 필드 수가 가장 적은 인덱스가 선택됩니다.
6.2 페이징 가능
이 API는 기본 FTS 인덱스에서 얻은 결과를 페이지화할 수 있는지 여부를 결정하는 데 사용됩니다. 인덱스가 페이지 가능한 경우 N1QL은 Search(..)를 실행하기 전에 FTS에 대한 필터(오프셋, 제한, 정렬 정보)를 적용하고, 그렇지 않으면 FTS가 전송된 후 결과 세트에 필터를 적용합니다.
N1QL 쿼리에 필터(오프셋, 제한, 주문 기준)가 없는 경우 이 API는 호출되지 않습니다.
6.3 검색
이 API는 가장 확장 가능한 인덱스에 대해 호출되며, 기본적으로 검색 요청을 FTS 인덱스에 전달하고 채널을 통해 결과를 다시 스트리밍하는 역할을 담당합니다. 스트리밍할 데이터의 양이 N1QL의 채널 끝에서 사용 가능한 버퍼 크기를 초과하면 FTS가 데이터를 파일로 다시 채우고 별도의 루틴이 이 콘텐츠를 N1QL로 스트리밍하는 작업을 담당합니다. 이는 N1QL의 느린 연결로 인해 FTS의 리소스가 지연되지 않도록 하기 위한 것입니다. 내부적으로 gRPC 프로토콜은 FTS에서 N1QL로 데이터를 스트리밍하는 데 사용됩니다.
6.4 확인: 평가
이 API는 N1QL에서 FTS 인덱스가 반환한 결과/히트가 쿼리에 실제로 유효한지 확인하기 위해 사용됩니다. FTS는 키 ID와 점수 등과 같은 일부 FTS 관련 메타데이터(요청된 경우)만 반환합니다. N1QL은 KV에서 문서를 가져와서 SELECT 술어가 일부 문서 필드에 대해 요청하는 경우 해당 문서에 대해 Verify를 호출합니다.
커버된 인덱스 쿼리 대 비커버된 인덱스 쿼리
SELECT 문의 조건문이 키 또는 메타데이터만 요청하는 경우 Verify API는 전혀 호출되지 않습니다. 이러한 종류의 쿼리를 커버 인덱스 쿼리. 다른 문서 콘텐츠에 대한 요청인 경우, N1QL은 FTS에서 반환된 키를 사용하여 KV에서 문서 데이터를 가져온 다음, 가져온 각 문서에 대해 Verify 메서드를 호출하여 검색된 문서가 실제로 유효한 일치 항목인지 다시 확인합니다. 이러한 종류의 쿼리를 커버되지 않는 인덱스 쿼리. 비 커버드 인덱스 쿼리는 각 히트에 대해 KV 가져오기 및 확인을 포함하므로 커버드 인덱스 쿼리보다 지연 시간이 더 길어지는 경향이 있습니다.
사용자가 문서의 다른 필드를 결과 집합의 일부로 포함시켜야 하는 경우, 원하는 필드를 저장하도록 FTS 인덱스 정의를 조정하는 것이 더 빠른 접근 방식입니다. 이제 SEARCH(...) 함수 내의 검색 요청에 "fields"라는 섹션을 포함하세요: ["*"]라는 섹션을 추가하여 저장된 모든 필드를 결과 집합의 일부로 가져옵니다. 이렇게 하면 N1QL은 별도의 문서 가져오기를 수행할 필요가 없으며 확인도 건너뛸 수 있습니다. 즉, 더 큰 FTS 인덱스의 비용으로 커버되지 않는 인덱스 쿼리를 커버되는 인덱스 쿼리로 변환하는 것입니다.
"국가" 및 "콘텐츠" 필드가 인덱싱된 다음 FTS 인덱스 정의를 고려하세요.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
{ "name": "sample", "type": "전체 텍스트 인덱스", "params": { "매핑": { "default_mapping": { "enabled": true, "동적": true, "속성": { "country": { "enabled": true, "동적": false, "fields": [ { "name": "country", "type": "text", "store": false, "index": true, "include_term_vectors": true, "docvalues": true } ] }, "content": { "enabled": true, "동적": false, "fields": [ { "name": "content", "type": "text", "store": false, "index": true, "docvalues": true } ] } } } } } } |
다음은 '국가' 필드에 '미국'이 있는 문서에 대해 문서 필드 '내용'을 가져오는 느린 비적용 인덱스 쿼리의 예입니다.
|
1 2 3 4 5 |
선택 메타().id, t.콘텐츠 FROM `여행-샘플` as t 어디 검색(t, {"쿼리": {"일치_문구": "united 상태", "필드": "국가"}}) 주문 BY search_score() DESC LIMIT 10; |
관심 있는 '콘텐츠' 필드도 저장하도록 인덱스 정의를 업데이트해 보겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
{ "name": "sample", "type": "전체 텍스트 인덱스", "params": { "매핑": { "default_mapping": { "enabled": true, "동적": true, "속성": { "country": { "enabled": true, "동적": false, "fields": [ { "name": "country", "type": "text", "store": false, "index": true, "include_term_vectors": true, "docvalues": true } ] }, "content": { "enabled": true, "동적": false, "fields": [ { "name": "content", "type": "text", "store": true, "index": true, "docvalues": true } ] } } } } } } |
이제 여기에 커버드 인덱스 쿼리에 해당하는 동일한 쿼리가 있습니다.
|
1 2 3 4 5 6 |
선택 메타(t).id, 메타.필드.콘텐츠 FROM `여행-샘플` as t LET 메타 = 검색_메타(t) 어디 검색(t, {"쿼리": {"일치_문구": "united 상태", "필드": "국가"}, "필드": ["콘텐츠"]}) 주문 BY search_score(t) DESC LIMIT 10; |
더 많은 N1QL+FTS 예제
8.1 복잡한 쿼리
N1QL 쿼리 내에서 복합 접속사/접속사 분리 FTS 검색 실행하기 ... 점수가 가장 높은 것부터 가장 낮은 것까지 정렬된 상위 100개의 문서 ID를 가져옵니다(FTS의 기본 점수 알고리즘인 tf-idf... 카테고리는 랜드마크이고 국가는 미국입니다).
|
1 2 3 4 5 |
선택 메타().id, search_score() as 점수 FROM `여행-샘플` as t 어디 검색(t, {"접속사": [{"일치": "랜드마크", "필드": 카테고리"}, {"일치_문구": "united 상태", "필드": "국가"}]}) 주문 BY 점수 DESC LIMIT 100; |
다음은 SEARCH(..) 함수 내에 FTS 설정이 포함된 동등한 쿼리입니다...
|
1 2 3 |
선택 메타().id, search_score() as 점수 FROM `여행-샘플` as t 어디 검색(t, {"쿼리": {"접속사": [{"일치": "랜드마크", "필드": 카테고리"}, {"일치_문구": "united 상태", "필드": "국가"}]}, "정렬": ["-_score"], "limit": 10}); |
SEARCH(...) 함수에 포함된 FTS 설정으로 다른 쿼리 실행하기 ... 점수를 고려하지 않고 설명 필드에 고딕이라는 용어가 포함된 모든 문서 ID를 가져옵니다. 여기서 점수를 전혀 결정하지 않도록 FTS 검색 요청을 최적화할 수 있습니다.
|
1 2 3 |
선택 메타().id FROM `여행-샘플` as t 어디 검색(t, {"쿼리": {"일치": "고딕", "필드": "설명"}, "점수": "없음"}); |
지원되는 다양한 FTS 쿼리 유형에 대해 자세히 설명합니다. 여기.
8.2 쿼리 정렬 가능성 대 인덱스 정의
FTS 인덱스 정의에 대해 쿼리가 사징 가능한 것으로 간주되는 방법에 대한 몇 가지 예를 살펴보기 전에, FTS 인덱스 정의에 대해 자세히 알아보세요. 여기.
"설명" 필드에서 "고딕"이라는 용어를 찾는 다음 쿼리를 생각해 보세요.
|
1 2 3 |
선택 메타().id, search_score() FROM `여행-샘플` 어디 검색(`여행-샘플`, {"쿼리": {"일치": "고딕", "필드": "설명"}); |
현재 사용 중인 카우치베이스 시스템에서 여러 개의 FTS 인덱스가 정의되어 있다고 가정해 보겠습니다.
우리가 접하는 첫 번째 FTS 인덱스의 정의는 다음과 같습니다.
|
1 2 3 4 5 6 7 8 9 10 11 |
{ "type": "전체 텍스트 인덱스", "params": { "매핑": { "default_mapping": { "enabled": true, "동적": true } } } } |
이 인덱스는 모든 문서에서 사용 가능한 모든 필드를 포함하며 기본 필드 "_all" 내의 콘텐츠도 포함하는 기본 동적 인덱스라고 합니다. 이 기본 필드는 FTS 쿼리가 검색 기준에 대한 '필드' 정보를 포함하지 않을 때 조사되는 필드입니다. 이 인덱스는 위의 쿼리에 대해 SARGABLE로 간주됩니다..
두 번째 FTS 인덱스의 정의는 다음과 같습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ "type": "전체 텍스트 인덱스", "params": { "매핑": { "default_mapping": { "enabled": true, "동적": false, "속성": { "설명": { "enabled": true, "동적": false, "fields": [ { "name": "설명", "type": "text", "store": false, "index": true, "include_term_vectors": true, "IN_IN_ALL": false, "docvalues": true } ] } } } } } } |
이 인덱스에는 쿼리의 요청을 충족하는 "설명" 필드만 인덱싱되어 있습니다. 인덱스는 쿼리에 대해 SARGABLE입니다..
세 번째 FTS 인덱스의 정의는 다음과 같습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
{ "type": "전체 텍스트 인덱스", "params": { "매핑": { "default_mapping": { "enabled": true, "동적": false, "속성": { "city": { "enabled": true, "동적": false, "fields": [ { "name": "city", "type": "text", "store": false, "index": true, "include_term_vectors": true, "IN_IN_ALL": true, "docvalues": true } ] }, "country": { "enabled": true, "동적": false, "fields": [ { "name": "country", "type": "text", "store": false, "index": true, "include_term_vectors": true, "IN_IN_ALL": true, "docvalues": true } ] }, "name": { "enabled": true, "동적": false, "fields": [ { "name": "name", "type": "text", "store": false, "index": true, "include_term_vectors": true, "IN_IN_ALL": false, "docvalues": true } ] } } } } } } |
이 인덱스에는 색인된 필드가 몇 개 있지만 요청된 필드 '설명'과 일치하는 필드는 없습니다. 이 인덱스는 쿼리에 대해 저장할 수 없는 것으로 간주됩니다..
이제 N1QL은 쿼리에 대해 정확한 결과를 제공할 수 있는 처음 2개의 인덱스 중에서 선택할 수 있는 옵션이 있습니다. 두 번째 인덱스 내에서 인덱싱되는 필드 수가 더 정확하고 적기 때문에(따라서 이 인덱스에서 검색이 더 빠르기 때문에) N1QL은 쿼리 실행을 위해 두 번째 인덱스를 선택합니다.
미래
- 요청된 모든 필드를 지원하지 않는 FTS 인덱스에서와 같이 FTS 인덱스 정의의 일부 유연성을 지원하여 검색 가능성을 개선합니다.
- 여러 유형 매핑이 있는 FTS 인덱스를 지원합니다.
- FTS 인덱스를 편집할 수 있도록 N1QL 쿼리 인터페이스 확장.
아주 좋은 기사 Abhinav, 방금 질문이 있습니다.
또한 지난 세 가지 예제에서와 마찬가지로 선택할 FTS 인덱스의 이름을 명시적으로 지정할 필요가 없습니다. N1QL은 사용 가능한 인덱스 중에서 FTS 쿼리를 실행하기에 가장 적합한 인덱스를 결정합니다. N1QL이 특정 인덱스(예: "travel"이라는 이름의 인덱스)를 사용하도록 하려면 다음과 같이 하세요.
검색 기능 내에서 FTS의 영역에 있기 때문에 FTS가 최상의 인덱스를 결정하지 않아야 하나요? 아니면 제가 뭔가 놓치고 있는 건가요?
FTS는 사용 가능한 모든 인덱스의 속성을 N1QL에 전달합니다.
N1QL은 쿼리 매개변수와 인덱스 속성을 기반으로 쿼리를 타겟팅할 인덱스를 선택합니다.
이 글루 코드는 http://github.com/couchbase/n1fty.
쿼리는 인덱스 이름을 속성으로 사용하여 FTS가 호스팅하는 엔드포인트를 대상으로 합니다.