
MongoDB Atlas 벡터 검색은 벡터 표현을 기반으로 효율적인 유사성 검색을 가능하게합니다. 이는 기존 키워드 기반 검색이 부족할 수있는 텍스트, 이미지 또는 오디오와 같은 구조화되지 않은 데이터로 작업 할 때 특히 유리합니다.
주요 장점 :
OpenFGA와의 통합 :
OpenFGA와 결합하면 MongoDB Atlas Vector Search는 안전한 문서 액세스를위한 강력한 솔루션을 제공합니다. 벡터 검색을 사용하여 컨텐츠를 기반으로 관련 문서를 검색 한 다음 OpenFGA의 액세스 제어 규칙을 적용하여 공인 사용자 만 결과를 볼 수 있도록 할 수 있습니다.
예:
사용자가 컨텐츠에 따라 문서를 검색 할 수있는 문서 관리 시스템을 상상해보십시오. MongoDB Atlas 벡터 검색을 사용하면 사용자의 쿼리와 의미 적으로 유사한 문서를 효율적으로 검색 할 수 있습니다. 그런 다음 OpenFGA를 사용하여 액세스 제어를 시행하여 사용자가 볼 권한이있는 문서 만 볼 수 있도록 할 수 있습니다.
OpenFGA는 클라우드 네이티브 애플리케이션에 세밀한 액세스 제어를 제공하도록 설계된 오픈 소스 인증 플랫폼입니다. 사용자 권한을 관리하고 리소스 액세스를위한 유연하고 확장 가능한 솔루션을 제공합니다.
OpenFGA는 튜플 의 개념에서 작동합니다. 튜플은 사용자, 관계 (예 : "읽기", "쓰기") 및 객체 (예 : 파일, 데이터베이스)로 구성된 권한을 나타냅니다. 정책은 허용되거나 거부되는 튜플을 지정하도록 정의됩니다. 사용자가 리소스에 액세스하려고 할 때 OpenFGA는 정의 된 정책에 대한 해당 튜플을 평가하여 액세스가 부여되는지 거부되는지 여부를 결정합니다.
OpenFGA Docker 이미지를 당기십시오 :
docker pull openfga/openfga노출 된 포트로 OpenFGA 컨테이너를 실행하십시오.
docker run -p 8080:8080 -p 3000:3000 openfga/openfga runMongodb Atlas Local Docker 이미지를 당기십시오 :
docker pull mongodb/mongodb-atlas-localMongoDB Atlas 로컬 컨테이너를 실행하십시오.
docker run -p 27017:27017 mongodb/mongodb-atlas-local이 섹션에서는 OpenFGA 데이터 내에서 효율적인 유사성 검색을위한 벡터 검색 색인을 작성하여 안내합니다.
mongosh 사용하여 로컬 아틀라스 클러스터에 연결하십시오.
mongosh " mongodb://localhost/demo?directConnection=true " demo 데이터베이스로 전환하십시오 (필요한 경우 실제 데이터베이스 이름으로 바꾸십시오) :
use demo
"Embeddings"필드에서 "vector_index"라는 벡터 검색 색인을 만듭니다.
db . mdb_fga . createSearchIndex (
"vector_index" ,
"vectorSearch" , // index type
{
fields : [
{
"type" : "vector" ,
"numDimensions" : 1536 ,
"path" : "embeddings" ,
"similarity" : "cosine"
} ,
]
}
) ;필요한 파이썬 라이브러리 설치
pip install asyncio requests pymongo unstructured openai 이 명령은 Python 코드를 실행하기 위해 필요한 모든 라이브러리 ( asyncio , requests , pymongo , unstructured 및 openai )를 설치합니다.
구조화되지 않은 : 문서에서 의미를 추출합니다
구조화되지 않은 것은 텍스트 문서를 더 작고 관리하기 쉬운 단위로 분류 할 수 있도록합니다. 연구 논문을 상상해보십시오. 구조화되지 않은 구조화는이를 섹션, 단락 또는 문장으로 나눌 수 있으므로 처리 및 분석이 더 쉽습니다. 도서관은 또한 이름, 날짜 및 위치와 같은 엔티티를 추출하여 정보 검색을 지원합니다.
OpenFGA : 추출 된 데이터에 대한 액세스 확보
귀하는 특정 조건에 따라 사용자 권한을 관리하는 정책을 정의합니다. 사용자가 문서 또는 추출 된 데이터에 액세스하려고 할 때 OpenFGA는 해당 사용자를 평가하고 이러한 정책에 대해 문서화하여 액세스를 부여하거나 거부합니다.
MongoDB Atlas 벡터 검색 : 유사한 문서를 효율적으로 찾습니다
문서 수집 내에서 특정 개념을 찾고 있다고 상상해보십시오. 키워드 기반 검색은 정확한 키워드가 포함되지 않은 관련 문서를 놓칠 수 있습니다. 그러나 벡터 검색은 문서 내용의 벡터 표현을 분석하여 다른 문구를 사용하더라도 의미 적으로 유사한 문서를 찾을 수 있습니다.
이러한 도구를 결합하는 힘
이 세 가지 도구를 통합하면 강력하고 안전한 문서 관리 시스템을 만듭니다. 워크 플로는 다음과 같습니다.
add_tuple 에 권한 추가 코드 스 니펫에서 본 add_tuple 기능은 MDB-OpenFGA 응용 프로그램 내에서 액세스 제어를 관리하는 데 중요한 역할을합니다. OpenFGA와 상호 작용하여 특정 리소스를 볼 수있는 사용자 권한을 부여합니다.
add_tuple 의 작동 방식에 대한 분석은 다음과 같습니다.
논쟁 :
USER : 이것은 허가를받는 사용자를 나타냅니다. 코드는 OpenFGA 내에서 일관성을위한 "user:"+USER 로 형식화합니다.RESOURCE : 이것은 사용자가 액세스 할 수있는 리소스를 나타냅니다. 이 예에서는 "doc:"+RESOURCE (문서를 가정)로 형식화됩니다.API 전화 :
/stores/{store_id}/write )에 대한 게시물 요청을 구성합니다. 이 엔드 포인트는 OpenFGA 상점에 데이터 (튜플)를 작성하는 데 사용됩니다.writes :이 키에는 추가 할 튜플을 지정하는 객체가 있습니다.tuple_keys : 이것은 권한을 정의하는 튜플 객체를 포함하는 배열입니다. 각 튜플 물체에는 세 가지 속성이 있습니다.user : 이전에 형식의 사용자 ID.relation : 이것은 허가 유형을 정의합니다. 이 경우 읽기 액세스를 표시하기 위해 "viewer" 로 설정됩니다.object : 앞에서 형식으로 지정된 리소스 ID.authorization_model_id : OpenFGA에서 사용되는 권한 화 모델의 ID를 지정합니다. 이 모델은 튜플을 평가하는 방식을 관리하는 액세스 제어 규칙을 정의합니다.응답:
본질적으로 add_tuple OpenFGA에서 새로운 튜플을 만듭니다. 특정 사용자 ( USER )는 특정 리소스 ( RESOURCE )를 볼 수있는 권한이 있다고 진술합니다. 그런 다음이 튜플은 OpenFGA의 액세스 제어 메커니즘에서 사용하여 향후 요청 중에 사용자가 리소스에 액세스 할 수있는 권한이 있는지 확인합니다.
check_authorization 이해 check_authorization 함수는 MDB-OPENFGA 응용 프로그램에서 중요한 역할을합니다. 주어진 사용자가 OpenFGA에 정의 된 액세스 제어 정책을 기반으로 특정 리소스에 액세스 할 수있는 권한이 있는지 확인해야합니다.
작동 방식 :
논쟁 :
tuple_key : 이것은 튜플을 나타내는 JSON 객체입니다. 아시다시피 튜플은 허가를 정의합니다. 일반적으로 세 가지 속성을 포함합니다.user : 사용자 ID.relation : 허가 유형 (예 : "Viewer", "Editor").object : 리소스 ID.API 전화 :
/stores/{store_id}/check 에 게시물 요청을 보냅니다. 이 엔드 포인트는 정의 된 인증 모델에 대한 튜플을 평가하는 데 사용됩니다.authorization_model_id : 사용중인 인증 모델의 ID.tuple_key : 확인하려는 튜플 객체.응답:
bool 값이 포함됩니다.true : 사용자는 허가가 있습니다.false : 사용자는 허가가 없습니다. 본질적으로, check_authorization 입력으로 튜플을 취하고 OpenFGA를 쿼리하기 위해 튜플에 지정된 사용자가 지정된 리소스 (객체)에서 동작 (관계)을 수행 할 수 있는지 확인합니다.
데모 실행
python3 demo.py
Starting FGA setup...
FGA setup response: {'code': 'write_failed_due_to_invalid_input', 'message': "cannot write a tuple which already exists: user: 'user:demo_user', relation: 'viewer', object: 'doc:demo.pdf': invalid write input"}
Clearing the db first...
Database cleared.
Starting PDF document partitioning...
PDF partitioning and database insertion completed successfully.
Waiting for index to be updated. This may take a few seconds...
Starting search tool...
Access Granted: User 'demo_user' has permission to read document 'demo.pdf'.
Access Denied: User 'demo_user-denyme' does not have permission to read document 'demo.pdf'.
import asyncio
import requests
import json
import pymongo
from unstructured . partition . auto import partition
from openai import AzureOpenAI
class FGA_MDB_DEMO :
def __init__ ( self , azure_endpoint , api_version , api_key , mongo_uri , fga_api_url , fga_store_id , fga_api_token , authorization_model_id , db_name , collection_name ):
self . az_client = AzureOpenAI ( azure_endpoint = azure_endpoint , api_version = api_version , api_key = api_key )
self . mongo_client = pymongo . MongoClient ( mongo_uri )
self . fga_api_url = fga_api_url
self . fga_store_id = fga_store_id
self . fga_api_token = fga_api_token
self . authorization_model_id = authorization_model_id
self . db_name = db_name
self . collection_name = collection_name
def generate_embeddings ( self , text , model = "" ):
return self . az_client . embeddings . create ( input = [ text ], model = model ). data [ 0 ]. embedding
def check_authorization ( self , tuple_key ):
url = f" { self . fga_api_url } /stores/ { self . fga_store_id } /check"
headers = {
"Authorization" : f"Bearer { self . fga_api_token } " ,
"content-type" : "application/json" ,
}
data = {
"authorization_model_id" : self . authorization_model_id ,
"tuple_key" : tuple_key
}
response = requests . post ( url , headers = headers , data = json . dumps ( data ))
return response . json ()
def add_tuple ( self , USER , RESOURCE ):
url = f" { self . fga_api_url } /stores/ { self . fga_store_id } /write"
headers = {
"Authorization" : f"Bearer { self . fga_api_token } " ,
"content-type" : "application/json" ,
}
data = {
"writes" : {
"tuple_keys" : [
{
"user" : "user:" + USER ,
"relation" : "viewer" ,
"object" : "doc:" + RESOURCE
}
]
},
"authorization_model_id" : self . authorization_model_id
}
response = requests . post ( url , headers = headers , data = json . dumps ( data ))
return response . json ()
def search_tool ( self , text , USER_ID ):
response = self . mongo_client [ self . db_name ][ self . collection_name ]. aggregate ([
{
"$vectorSearch" : {
"index" : "vector_index" ,
"queryVector" : self . az_client . embeddings . create ( model = "text-embedding-ada-002" , input = text ). data [ 0 ]. embedding ,
"path" : "embeddings" ,
"limit" : 5 ,
"numCandidates" : 30
}
}, { "$project" :{ "_id" : 0 , "embeddings" : 0 , "metadata" : 0 }}
])
for doc in response :
tuple_key = { "user" : "user:" + USER_ID , "relation" : "viewer" , "object" : "doc:" + doc [ "source" ]}
response = self . check_authorization ( tuple_key )
if response [ 'allowed' ]:
print ( f"Access Granted: User ' { USER_ID } ' has permission to read document ' { doc [ 'source' ] } '." )
else :
print ( f"Access Denied: User ' { USER_ID } ' does not have permission to read document ' { doc [ 'source' ] } '." )
def partition_pdf ( self , resource ):
mdb_db = self . mongo_client [ self . db_name ]
mdb_collection = mdb_db [ self . collection_name ]
print ( "Clearing the db first..." )
mdb_collection . delete_many ({})
print ( "Database cleared." )
print ( "Starting PDF document partitioning..." )
elements = partition ( resource )
for element in elements :
mdb_collection . insert_one ({
"text" : str ( element . text ),
"embeddings" : self . generate_embeddings ( str ( element . text ), "text-embedding-ada-002" ),
"metadata" : {
"raw_element" : element . to_dict (),
},
"source" : resource
})
print ( "PDF partitioning and database insertion completed successfully." )
def fga_setup ( self , user , resource ):
response = self . add_tuple ( user , resource )
print ( f"FGA setup response: { response } " )
async def main ( self , user , resource ):
print ( "Starting FGA setup..." )
self . fga_setup ( user , resource )
self . partition_pdf ( resource )
print ( "Waiting for index to be updated. This may take a few seconds..." )
await asyncio . sleep ( 15 )
print ( "Starting search tool..." )
self . search_tool ( "test" , user )
self . search_tool ( "test" , user + "-denyme" )
print ( "Process completed successfully." )
if __name__ == "__main__" :
fga_mdb_demo = FGA_MDB_DEMO (
azure_endpoint = "" ,
api_version = "2024-04-01-preview" ,
api_key = "" ,
mongo_uri = "mongodb://localhost:27017/demo?directConnection=true" ,
fga_api_url = 'http://localhost:8080' ,
fga_store_id = '01J8VP1HYCHN459VT76DQG0W2R' ,
fga_api_token = '' ,
authorization_model_id = '01J8VP3BMPZNFJ480G5ZNF3H0C' ,
db_name = "demo" ,
collection_name = "mdb_fga"
)
asyncio . run ( fga_mdb_demo . main ( "demo_user" , "demo.pdf" ))