from abc import ABC, abstractmethod from dataclasses import dataclass from typing import Any, Dict, List from slugify import slugify from server.db.es_connector import ES_INSTANCE __all__ = ["SeachByNameHelper", "SeachByNameBaseObject"] @dataclass class SeachByNameBaseObject: entity_type: str entity_id: str class SeachByNameHelper(ABC): _es_connector = ES_INSTANCE @property @abstractmethod def _index_name(self) -> str: pass @abstractmethod async def get_data(self, results: List[Dict[str, Any]]) -> List[Dict[str, Any]]: pass def _get_query(self, params: Dict[str, Any]) -> Dict[str, Any]: query: dict = {"match": {}} for key, value in params.items(): query = { "bool": { "should": [ {"term": {f"{key}.keyword": {"value": value, "boost": 10000}}}, {"term": {f"slugified_{key}.keyword": {"value": slugify(value, separator=""), "boost": 10000}}}, {"prefix": {f"{key}.keyword": {"value": value, "boost": 1000, "case_insensitive": True}}}, {"match": {key: {"query": value, "operator": "AND", "fuzziness": 0, "boost": 100}}}, {"match": {key: {"query": value, "operator": "AND", "fuzziness": "AUTO", "boost": 10}}}, ] }, } return query def _get_sort(self) -> Dict[str, Any]: return {"_score": "desc"} async def _get_results(self, params: Dict[str, Any], *, limit: int, offset: int) -> List[Dict[str, Any]]: query = self._get_query(params) sort = self._get_sort() _, data, _ = await self._es_connector.search( index=self._index_name, query=query, sort=sort, from_=offset, size=limit ) results: List[Dict[str, Any]] = [] for result in data: tmp = result["_source"] tmp.update({"id": result["_id"], "score": result["_score"]}) results.append(tmp) return results async def search(self, params: Dict[str, Any]): limit, offset = params.pop("limit"), params.pop("offset") results = await self._get_results(params, limit=limit, offset=offset) if not results: return [] return self.get_data(results) # type: ignore