# 의미적 유사성으로 문서 검색

{% openapi src="<https://2913883985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs0e4JCKQXzEGPRlMO7nt%2Fuploads%2Fgit-blob-77b6137eeb641262ec8e531c78123c02b825b865%2Frememberizer_openapi.yml?alt=media&token=ac0eeb18-73cf-42a3-93fe-2ff232a978a3>" path="/documents/search/" method="get" %}
[rememberizer\_openapi.yml](https://2913883985-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs0e4JCKQXzEGPRlMO7nt%2Fuploads%2Fgit-blob-77b6137eeb641262ec8e531c78123c02b825b865%2Frememberizer_openapi.yml?alt=media\&token=ac0eeb18-73cf-42a3-93fe-2ff232a978a3)
{% endopenapi %}

## 예제 요청

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X GET \
  "https://api.rememberizer.ai/api/v1/documents/search/?q=How%20to%20integrate%20Rememberizer%20with%20custom%20applications&n=5&from=2023-01-01T00:00:00Z&to=2023-12-31T23:59:59Z" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

{% hint style="info" %}
`YOUR_JWT_TOKEN`을 실제 JWT 토큰으로 교체하세요.
{% endhint %}
{% endtab %}

{% tab title="JavaScript" %}

```javascript
const searchDocuments = async (query, numResults = 5, from = null, to = null) => {
  const url = new URL('https://api.rememberizer.ai/api/v1/documents/search/');
  url.searchParams.append('q', query);
  url.searchParams.append('n', numResults);
  
  if (from) {
    url.searchParams.append('from', from);
  }
  
  if (to) {
    url.searchParams.append('to', to);
  }
  
  const response = await fetch(url.toString(), {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_JWT_TOKEN'
    }
  });
  
  const data = await response.json();
  console.log(data);
};

searchDocuments('How to integrate Rememberizer with custom applications', 5);
```

{% hint style="info" %}
`YOUR_JWT_TOKEN`을 실제 JWT 토큰으로 교체하세요.
{% endhint %}
{% endtab %}

{% tab title="Python" %}

```python
import requests

def search_documents(query, num_results=5, from_date=None, to_date=None):
    headers = {
        "Authorization": "Bearer YOUR_JWT_TOKEN"
    }
    
    params = {
        "q": query,
        "n": num_results
    }
    
    if from_date:
        params["from"] = from_date
    
    if to_date:
        params["to"] = to_date
    
    response = requests.get(
        "https://api.rememberizer.ai/api/v1/documents/search/",
        headers=headers,
        params=params
    )
    
    data = response.json()
    print(data)

search_documents("How to integrate Rememberizer with custom applications", 5)
```

{% hint style="info" %}
`YOUR_JWT_TOKEN`을 실제 JWT 토큰으로 교체하세요.
{% endhint %}
{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'net/http'
require 'uri'
require 'json'

def search_documents(query, num_results=5, from_date=nil, to_date=nil)
  uri = URI('https://api.rememberizer.ai/api/v1/documents/search/')
  params = {
    q: query,
    n: num_results
  }
  
  params[:from] = from_date if from_date
  params[:to] = to_date if to_date
  
  uri.query = URI.encode_www_form(params)
  
  request = Net::HTTP::Get.new(uri)
  request['Authorization'] = 'Bearer YOUR_JWT_TOKEN'
  
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  
  response = http.request(request)
  data = JSON.parse(response.body)
  puts data
end

search_documents("How to integrate Rememberizer with custom applications", 5)
```

{% hint style="info" %}
`YOUR_JWT_TOKEN`을 실제 JWT 토큰으로 교체하세요.
{% endhint %}
{% endtab %}
{% endtabs %}

## 쿼리 매개변수

| 매개변수         | 유형  | 설명                                                    |
| ------------ | --- | ----------------------------------------------------- |
| q            | 문자열 | **필수.** 검색 쿼리 텍스트(최대 400단어).                          |
| n            | 정수  | 반환할 결과 수. 기본값: 3. 더 포괄적인 결과를 위해 더 높은 값(예: 10)을 사용하세요. |
| from         | 문자열 | 검색할 문서의 시간 범위 시작, ISO 8601 형식.                        |
| to           | 문자열 | 검색할 문서의 시간 범위 종료, ISO 8601 형식.                        |
| prev\_chunks | 정수  | 문맥을 포함할 이전 청크 수. 기본값: 2.                              |
| next\_chunks | 정수  | 문맥을 포함할 다음 청크 수. 기본값: 2.                              |

## 응답 형식

```json
{
  "data_sources": [
    {
      "name": "Google Drive",
      "documents": 3
    },
    {
      "name": "Slack",
      "documents": 2
    }
  ],
  "matched_chunks": [
    {
      "document": {
        "id": 12345,
        "document_id": "1aBcD2efGhIjK3lMnOpQrStUvWxYz",
        "name": "Rememberizer API Documentation.pdf",
        "type": "application/pdf",
        "path": "/Documents/Rememberizer/API Documentation.pdf",
        "url": "https://drive.google.com/file/d/1aBcD2efGhIjK3lMnOpQrStUvWxYz/view",
        "size": 250000,
        "created_time": "2023-05-10T14:30:00Z",
        "modified_time": "2023-06-15T09:45:00Z",
        "indexed_on": "2023-06-15T10:30:00Z",
        "integration": {
          "id": 101,
          "integration_type": "google_drive"
        }
      },
      "matched_content": "Rememberizer를 사용자 정의 애플리케이션과 통합하려면 OAuth2 인증 흐름을 사용하여 애플리케이션이 사용자의 Rememberizer 데이터에 접근할 수 있도록 권한을 부여할 수 있습니다. 권한이 부여되면 애플리케이션은 Rememberizer API를 사용하여 문서를 검색하고, 콘텐츠를 검색하며, 그 외의 작업을 수행할 수 있습니다.",
      "distance": 0.123
    },
    // ... 더 많은 일치하는 청크
  ],
  "message": "검색이 성공적으로 완료되었습니다",
  "code": "success"
}
```

## 검색 최적화 팁

### 질문 답변을 위한

질문에 대한 답을 찾을 때, 쿼리를 이상적인 답변처럼 구성해 보세요. 예를 들어:

대신: "벡터 임베딩이란 무엇인가?" 시도해 보세요: "벡터 임베딩은 텍스트를 고차원 공간의 숫자 벡터로 변환하는 기술입니다."

{% hint style="info" %}
벡터 임베딩이 어떻게 작동하는지와 이 검색 접근 방식이 효과적인 이유에 대한 더 깊은 이해를 원하시면 [벡터 임베딩과 벡터 데이터베이스란 무엇인가?](https://docs.rememberizer.ai/ko/background/what-are-vector-embeddings-and-vector-databases)를 참조하세요.
{% endhint %}

### 결과 수 조정

* 빠르고 높은 관련성의 결과를 위해 `n=3`으로 시작
* 더 포괄적인 정보를 위해 `n=10` 이상으로 증가
* 검색 결과가 불충분하면 `n` 매개변수를 증가시켜 보세요

### 시간 기반 필터링

`from` 및 `to` 매개변수를 사용하여 특정 기간의 문서에 집중하세요:

* 최근 문서: `from`을 최근 날짜로 설정
* 역사적 분석: 특정 날짜 범위를 지정
* 오래된 정보 제외: 적절한 `to` 날짜 설정

## 배치 작업

대량의 검색 쿼리를 효율적으로 처리하기 위해 Rememberizer는 성능을 최적화하고 API 호출 오버헤드를 줄이기 위한 배치 작업을 지원합니다.

### 배치 검색

{% tabs %}
{% tab title="Python" %}

```python
import requests
import time
import json
from concurrent.futures import ThreadPoolExecutor

def batch_search_documents(queries, num_results=5, batch_size=10):
    """
    여러 쿼리로 배치 검색 수행
    
    Args:
        queries: 검색 쿼리 문자열 목록
        num_results: 쿼리당 반환할 결과 수
        batch_size: 병렬로 처리할 쿼리 수
    
    Returns:
        각 쿼리에 대한 검색 결과 목록
    """
    headers = {
        "Authorization": "Bearer YOUR_JWT_TOKEN",
        "Content-Type": "application/json"
    }
    
    results = []
    
    # 쿼리를 배치로 처리
    for i in range(0, len(queries), batch_size):
        batch = queries[i:i+batch_size]
        
        # 요청을 병렬로 보내기 위한 스레드 풀 생성
        with ThreadPoolExecutor(max_workers=batch_size) as executor:
            futures = []
            
            for query in batch:
                params = {
                    "q": query,
                    "n": num_results
                }
                
                future = executor.submit(
                    requests.get,
                    "https://api.rememberizer.ai/api/v1/documents/search/",
                    headers=headers,
                    params=params
                )
                futures.append(future)
            
            # 완료되는 대로 결과 수집
            for future in futures:
                response = future.result()
                results.append(response.json())
        
        # 속도 제한 - API 제한을 피하기 위해 배치 사이에 일시 중지
        if i + batch_size < len(queries):
            time.sleep(1)
    
    return results

# 예제 사용법
queries = [
    "Rememberizer와 함께 OAuth 사용 방법",
    "벡터 데이터베이스 구성 옵션",
    "의미 기반 검색을 위한 모범 사례",
    # 필요에 따라 더 많은 쿼리 추가
]

results = batch_search_documents(queries, num_results=3, batch_size=5)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
/**
 * 여러 쿼리로 배치 검색 수행
 * 
 * @param {string[]} queries - 검색 쿼리 문자열 목록
 * @param {number} numResults - 쿼리당 반환할 결과 수
 * @param {number} batchSize - 병렬로 처리할 쿼리 수
 * @param {number} delayBetweenBatches - 배치 간 대기할 밀리초
 * @returns {Promise<Array>} - 각 쿼리에 대한 검색 결과 목록
 */
async function batchSearchDocuments(queries, numResults = 5, batchSize = 10, delayBetweenBatches = 1000) {
  const results = [];
  
  // 배치로 쿼리 처리
  for (let i = 0; i < queries.length; i += batchSize) {
    const batch = queries.slice(i, i + batchSize);
    
    // 동시 요청을 위한 프로미스 배열 생성
    const batchPromises = batch.map(query => {
      const url = new URL('https://api.rememberizer.ai/api/v1/documents/search/');
      url.searchParams.append('q', query);
      url.searchParams.append('n', numResults);
      
      return fetch(url.toString(), {
        method: 'GET',
        headers: {
          'Authorization': 'Bearer YOUR_JWT_TOKEN'
        }
      }).then(response => response.json());
    });
    
    // 배치의 모든 요청이 완료될 때까지 대기
    const batchResults = await Promise.all(batchPromises);
    results.push(...batchResults);
    
    // 속도 제한 - API 제한을 피하기 위해 배치 간 일시 정지
    if (i + batchSize < queries.length) {
      await new Promise(resolve => setTimeout(resolve, delayBetweenBatches));
    }
  }
  
  return results;
}

// 예제 사용법
const queries = [
  "Rememberizer와 함께 OAuth 사용 방법",
  "벡터 데이터베이스 구성 옵션",
  "의미 기반 검색을 위한 모범 사례",
  // 필요에 따라 더 많은 쿼리 추가
];

batchSearchDocuments(queries, 3, 5)
  .then(results => console.log(results))
  .catch(error => console.error('배치 검색 중 오류 발생:', error));
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'net/http'
require 'uri'
require 'json'
require 'concurrent'

# 여러 쿼리로 배치 검색 수행
#
# @param queries [Array<String>] 검색 쿼리 문자열 목록
# @param num_results [Integer] 쿼리당 반환할 결과 수
# @param batch_size [Integer] 병렬로 처리할 쿼리 수
# @param delay_between_batches [Float] 배치 간 대기할 초
# @return [Array] 각 쿼리에 대한 검색 결과 목록
def batch_search_documents(queries, num_results = 5, batch_size = 10, delay_between_batches = 1.0)
  results = []
  
  # 배치로 쿼리 처리
  queries.each_slice(batch_size).with_index do |batch, batch_index|
    # 동시 요청을 위한 스레드 풀 생성
    pool = Concurrent::FixedThreadPool.new(batch_size)
    futures = []
    
    batch.each do |query|
      futures << Concurrent::Future.execute(executor: pool) do
        uri = URI('https://api.rememberizer.ai/api/v1/documents/search/')
        params = {
          q: query,
          n: num_results
        }
        
        uri.query = URI.encode_www_form(params)
        
        request = Net::HTTP::Get.new(uri)
        request['Authorization'] = 'Bearer YOUR_JWT_TOKEN'
        
        http = Net::HTTP.new(uri.host, uri.port)
        http.use_ssl = true
        
        response = http.request(request)
        JSON.parse(response.body)
      end
    end
    
    # 모든 스레드에서 결과 수집
    batch_results = futures.map(&:value)
    results.concat(batch_results)
    
    # 속도 제한 - API 제한을 피하기 위해 배치 사이에 일시 중지
    if batch_index < (queries.length / batch_size.to_f).ceil - 1
      sleep(delay_between_batches)
    end
  end
  
  pool.shutdown
  results
end

# 예제 사용법
queries = [
  "Rememberizer와 함께 OAuth 사용 방법",
  "벡터 데이터베이스 구성 옵션",
  "의미 검색을 위한 모범 사례",
  # 필요에 따라 더 많은 쿼리 추가
]

results = batch_search_documents(queries, 3, 5)
puts results
```

{% endtab %}
{% endtabs %}

### 성능 고려사항

배치 작업을 구현할 때 다음의 모범 사례를 고려하십시오:

1. **최적의 배치 크기**: 5-10 쿼리의 배치 크기로 시작하고 애플리케이션의 성능 특성에 따라 조정하십시오.
2. **요금 제한**: API 제한을 방지하기 위해 배치 간에 지연을 포함하십시오. 배치 간 1초가 좋은 시작점입니다.
3. **오류 처리**: 배치 내에서 실패한 요청을 관리하기 위해 강력한 오류 처리를 구현하십시오.
4. **자원 관리**: 특히 큰 배치 크기로 클라이언트 측 자원 사용을 모니터링하여 과도한 메모리 소비를 방지하십시오.
5. **응답 처리**: 가능한 경우 비동기적으로 배치 결과를 처리하여 사용자 경험을 개선하십시오.

대량의 애플리케이션의 경우, 많은 검색 요청을 효율적으로 관리하기 위해 큐 시스템을 구현하는 것을 고려하십시오.

이 엔드포인트는 전체 지식 기반에 걸쳐 강력한 의미 검색 기능을 제공합니다. 이는 의미에 따라 콘텐츠를 찾기 위해 벡터 임베딩을 사용하며, 정확한 키워드 일치가 아닙니다.
