This commit is contained in:
parent
4b83f5d0f5
commit
2222f6fc19
|
@ -1,6 +1,8 @@
|
|||
import time
|
||||
|
||||
from sqlalchemy import JSON, Boolean, Column, ForeignKey, Integer, String
|
||||
from sqlalchemy_utils import TSVectorType
|
||||
|
||||
from services.db import Base
|
||||
|
||||
|
||||
|
@ -38,3 +40,5 @@ class Author(Base):
|
|||
last_seen = Column(Integer, nullable=False, default=lambda: int(time.time()))
|
||||
updated_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
|
||||
deleted_at = Column(Integer, nullable=True, comment='Deleted at')
|
||||
|
||||
search_vector = Column(TSVectorType("name", "slug", "bio", "about"))
|
||||
|
|
|
@ -22,6 +22,7 @@ opensearch-py = "^2.4.2"
|
|||
httpx = "^0.26.0"
|
||||
dogpile-cache = "^1.3.1"
|
||||
colorlog = "^6.8.2"
|
||||
sqlalchemy-searchable = "^2.1.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
ruff = "^0.2.1"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import json
|
||||
import time
|
||||
|
||||
from sqlalchemy import desc, select, or_, and_, func
|
||||
from sqlalchemy import desc, select, or_, and_
|
||||
from sqlalchemy.orm import aliased
|
||||
from sqlalchemy_searchable import search
|
||||
|
||||
from orm.author import Author, AuthorFollower
|
||||
from orm.shout import ShoutAuthor, ShoutTopic
|
||||
|
@ -212,9 +213,5 @@ def get_author_followers(_, _info, slug: str):
|
|||
|
||||
@query.field('search_authors')
|
||||
def search_authors(_, info, text: str):
|
||||
v1 = func.to_tsquery('russian', text)
|
||||
v2 = func.to_tsvector(
|
||||
'russian', Author.name or ' ' or Author.bio or ' ' or Author.about
|
||||
)
|
||||
q = select(Author).filter(v2.match(v1))
|
||||
q = search(select(Author), text)
|
||||
return get_with_stat(q)
|
||||
|
|
26
services/cache.py
Normal file
26
services/cache.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from functools import wraps
|
||||
|
||||
from dogpile.cache import make_region
|
||||
|
||||
# Создание региона кэша с TTL 300 секунд
|
||||
cache_region = make_region().configure('dogpile.cache.memory', expiration_time=300)
|
||||
|
||||
|
||||
# Декоратор для кэширования методов
|
||||
def cache_method(cache_key: str):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# Генерация ключа для кэширования
|
||||
key = cache_key.format(*args, **kwargs)
|
||||
# Получение значения из кэша
|
||||
result = cache_region.get(key)
|
||||
if result is None:
|
||||
# Если значение отсутствует в кэше, вызываем функцию и кэшируем результат
|
||||
result = f(*args, **kwargs)
|
||||
cache_region.set(key, result)
|
||||
return result
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
|
@ -1,14 +1,14 @@
|
|||
import math
|
||||
import time
|
||||
from functools import wraps
|
||||
from sqlalchemy import event, Engine, inspect, text
|
||||
|
||||
from typing import Any, Callable, Dict, TypeVar
|
||||
|
||||
from dogpile.cache import make_region
|
||||
from sqlalchemy import exc, Column, Integer, create_engine
|
||||
from sqlalchemy import exc, event, Engine, inspect, Column, Integer, create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.sql.schema import Table
|
||||
from sqlalchemy_searchable import make_searchable
|
||||
|
||||
from services.logger import root_logger as logger
|
||||
from settings import DB_URL
|
||||
import warnings
|
||||
|
@ -31,17 +31,14 @@ warnings.simplefilter('always', exc.SAWarning)
|
|||
warnings.showwarning = warning_with_traceback
|
||||
warnings.simplefilter('always', exc.SAWarning)
|
||||
|
||||
# Создание региона кэша с TTL 300 секунд
|
||||
cache_region = make_region().configure('dogpile.cache.memory', expiration_time=300)
|
||||
|
||||
# Подключение к базе данных SQLAlchemy
|
||||
engine = create_engine(DB_URL, echo=False, pool_size=10, max_overflow=20)
|
||||
inspector = inspect(engine)
|
||||
T = TypeVar('T')
|
||||
REGISTRY: Dict[str, type] = {}
|
||||
|
||||
|
||||
# Перехватчики для журнала запросов SQLAlchemy
|
||||
# noinspection PyUnusedLocal
|
||||
@event.listens_for(Engine, 'before_cursor_execute')
|
||||
def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
|
||||
conn.query_start_time = time.time()
|
||||
|
@ -92,54 +89,4 @@ class Base(declarative_base()):
|
|||
setattr(self, key, value)
|
||||
|
||||
|
||||
# Декоратор для кэширования методов
|
||||
def cache_method(cache_key: str):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# Генерация ключа для кэширования
|
||||
key = cache_key.format(*args, **kwargs)
|
||||
# Получение значения из кэша
|
||||
result = cache_region.get(key)
|
||||
if result is None:
|
||||
# Если значение отсутствует в кэше, вызываем функцию и кэшируем результат
|
||||
result = f(*args, **kwargs)
|
||||
cache_region.set(key, result)
|
||||
return result
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
inspector = inspect(engine)
|
||||
|
||||
|
||||
def add_pg_trgm_extension_if_not_exists():
|
||||
with local_session() as session:
|
||||
result = session.execute(text("SELECT 1 FROM pg_extension WHERE extname = 'pg_trgm';"))
|
||||
if not result.scalar():
|
||||
session.execute(text("CREATE EXTENSION IF NOT EXISTS pg_trgm;"))
|
||||
print("pg_trgm extension added successfully.")
|
||||
else:
|
||||
print("pg_trgm extension already exists.")
|
||||
|
||||
|
||||
def create_fts_index(table_name, fts_index_name):
|
||||
add_pg_trgm_extension_if_not_exists()
|
||||
logger.info(f'Full text index for {table_name}...')
|
||||
authors_indexes = inspector.get_indexes(table_name)
|
||||
author_fts_index_exists = any(
|
||||
index['name'] == fts_index_name for index in authors_indexes
|
||||
)
|
||||
if not author_fts_index_exists:
|
||||
with local_session() as session:
|
||||
q = text("""
|
||||
CREATE INDEX {index_name} ON {author_table_name}
|
||||
USING gin(to_tsvector('russian', COALESCE(name,'') || ' ' || COALESCE(bio,'') || ' ' || COALESCE(about,'')));
|
||||
""".format(index_name=fts_index_name, author_table_name=table_name))
|
||||
session.execute(q)
|
||||
logger.info('Full text index created successfully.')
|
||||
|
||||
|
||||
create_fts_index('author', 'author_fts_idx')
|
||||
make_searchable(Base.metadata)
|
||||
|
|
Loading…
Reference in New Issue
Block a user