Feat: [#71] atlas search를 활용한 검색 기능 구현 완료

This commit is contained in:
sm4640
2025-07-27 23:50:02 +09:00
parent 8d7c2aa48b
commit 108eed65dd
11 changed files with 188 additions and 0 deletions

112
homes/services.py Normal file
View File

@@ -0,0 +1,112 @@
from django.conf import settings
import certifi
from pymongo import MongoClient
from django.db.models import Case, When, IntegerField
from projects.models import Project
from portfolios.models import Portfolio
NOCODETOOL_MODEL_MAP = {
'project': Project,
'portfolio': Portfolio,
}
class NocodetoolSearchService:
@staticmethod
def search(search_term, object_type, page, page_size):
client = MongoClient(settings.MONGODB_URI, tlsCAFile=certifi.where())
db = client[settings.MONGODB_NAME]
coll = db["code"]
filters = []
if object_type in ("project", "portfolio"):
filters.append({"term": {"path": "object_type", "query": object_type}})
pipeline = [
{
"$search": {
"index": "nocodetool_content_keyword_search_index",
"compound": {
"filter": filters,
"should": [
{
"text": {
"query": search_term,
"path": "keyword",
"score": {"boost": {"value": 5}}
}
},
{
"text": {
"query": search_term,
"path": "pages.elements.content",
"score": {"boost": {"value": 10}}
}
},
{
"text": {
"query": search_term,
"path": "description",
"score": {"boost": {"value": 7}}
}
}
],
"minimumShouldMatch": 1
}
}
},
{
"$project": {
"keyword": 1,
"description": 1,
"pages.elements.content": 1,
"object_type": 1,
"object_id": 1,
"score": {"$meta": "searchScore"}
}
},
{
"$facet": {
"projects": [
{"$match": {"object_type": "project"}},
{"$sort": {"score": -1}},
{"$skip": (page - 1) * page_size},
{"$limit": page_size}
],
"portfolios": [
{"$match": {"object_type": "portfolio"}},
{"$sort": {"score": -1}},
{"$skip": (page - 1) * page_size},
{"$limit": page_size}
]
}
}
]
agg_result = list(coll.aggregate(pipeline))
print(agg_result)
buckets = agg_result[0] if agg_result else {"projects": [], "portfolios": []}
return buckets
def get_ids_from_buckets(buckets: list) -> list:
return [object["object_id"] for object in buckets]
class NocodetoolToObjectService:
def get_objects_by_ids(object_type, objects_ids: list) -> list:
if not objects_ids:
return []
order = Case(
*[When(id=pk, then=pos) for pos, pk in enumerate(objects_ids)],
output_field=IntegerField()
)
object_model = NOCODETOOL_MODEL_MAP.get(object_type)
if not object_model:
return []
return list(object_model.objects.filter(id__in=objects_ids).order_by(order))