mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Perserving ts_rank when searching.
This commit is contained in:
parent
f9c02608e6
commit
b81e00ff3d
8 changed files with 30 additions and 23 deletions
|
|
@ -6,7 +6,7 @@ import sqlalchemy
|
|||
from modules.videos.common import apply_info_json
|
||||
from modules.videos.lib import parse_video_file_name, validate_video, get_statistics
|
||||
from modules.videos.models import Video
|
||||
from modules.videos.video.lib import video_search
|
||||
from modules.videos.video.lib import search_videos
|
||||
from wrolpi.files import lib as files_lib
|
||||
from wrolpi.files.models import File
|
||||
|
||||
|
|
@ -27,19 +27,19 @@ def test_search_censored_videos(test_session, simple_channel, video_factory):
|
|||
|
||||
# All source_ids are in the entries.
|
||||
set_entries(map(str, range(50)))
|
||||
videos, total = video_search(filters=['censored'], order_by='id', limit=20)
|
||||
videos, total = search_videos(filters=['censored'], order_by='id', limit=20)
|
||||
assert [i['video']['source_id'] for i in videos] == []
|
||||
assert total == 0
|
||||
|
||||
# First 5 are censored.
|
||||
set_entries(map(str, range(5, 50)))
|
||||
videos, total = video_search(filters=['censored'], order_by='id', limit=20)
|
||||
videos, total = search_videos(filters=['censored'], order_by='id', limit=20)
|
||||
assert [i['video']['source_id'] for i in videos] == [str(i) for i in range(5)]
|
||||
assert total == 5
|
||||
|
||||
# First 25 are censored.
|
||||
set_entries(map(str, range(25, 50)))
|
||||
videos, total = video_search(filters=['censored'], order_by='id', limit=20)
|
||||
videos, total = search_videos(filters=['censored'], order_by='id', limit=20)
|
||||
assert [i['video']['source_id'] for i in videos] == [str(i) for i in range(20)]
|
||||
assert total == 25
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ async def search(_: Request, body: schema.VideoSearchRequest):
|
|||
if body.order_by not in lib.VIDEO_ORDERS:
|
||||
raise InvalidOrderBy('Invalid order by')
|
||||
|
||||
files, videos_total = lib.video_search(
|
||||
files, videos_total = lib.search_videos(
|
||||
body.search_str,
|
||||
body.offset,
|
||||
body.limit,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ DEFAULT_VIDEO_ORDER = 'rank'
|
|||
VIDEO_QUERY_LIMIT = 24
|
||||
|
||||
|
||||
def video_search(
|
||||
def search_videos(
|
||||
search_str: str = None,
|
||||
offset: int = None,
|
||||
limit: int = VIDEO_QUERY_LIMIT,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import logging
|
||||
from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
from typing import ContextManager, Tuple, List, Union, Type
|
||||
|
|
@ -160,10 +159,10 @@ def optional_session(commit: Union[callable, bool] = False):
|
|||
|
||||
|
||||
@optional_session
|
||||
def get_ranked_models(ranked_ids: List, model: Type[Base], session: Session = None) -> List[Base]:
|
||||
"""Get all objects whose ids are in the `ranked_ids`, order them by their position in `ranked_ids`."""
|
||||
def get_ranked_models(ranked_primary_keys: List, model: Type[Base], session: Session = None) -> List[Base]:
|
||||
"""Get all objects whose primary keys are in the `ranked_primary_keys`, preserve their order."""
|
||||
pkey = inspect(model).primary_key[0]
|
||||
pkey_name = pkey.name
|
||||
results = list(session.query(model).filter(pkey.in_(ranked_ids)).all())
|
||||
results = sorted(results, key=lambda i: ranked_ids.index(getattr(i, pkey_name)))
|
||||
results = list(session.query(model).filter(pkey.in_(ranked_primary_keys)).all())
|
||||
results = sorted(results, key=lambda i: ranked_primary_keys.index(getattr(i, pkey_name)))
|
||||
return results
|
||||
|
|
|
|||
|
|
@ -98,6 +98,6 @@ async def refresh_directory(_: Request, body: schema.DirectoryRefreshRequest):
|
|||
body=schema.FilesSearchRequest,
|
||||
)
|
||||
@validate(schema.FilesSearchRequest)
|
||||
async def search_files(_: Request, body: schema.FilesSearchRequest):
|
||||
files, total = lib.file_search(body.search_str, body.limit, body.offset, body.mimetype, body.model)
|
||||
async def post_search_files(_: Request, body: schema.FilesSearchRequest):
|
||||
files, total = lib.search_files(body.search_str, body.limit, body.offset, body.mimetype, body.model)
|
||||
return json_response(dict(files=files, totals=dict(files=total)))
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ except ImportError:
|
|||
|
||||
logger = logger.getChild(__name__)
|
||||
|
||||
__all__ = ['list_files', 'delete_file', 'split_path_stem_and_suffix', 'refresh_files', 'file_search', 'get_mimetype']
|
||||
__all__ = ['list_files', 'delete_file', 'split_path_stem_and_suffix', 'refresh_files', 'search_files', 'get_mimetype']
|
||||
|
||||
|
||||
def filter_parent_directories(directories: List[Path]) -> List[Path]:
|
||||
|
|
@ -276,8 +276,8 @@ async def refresh_directory_files_recursively(directory: Union[pathlib.Path, str
|
|||
refresh_logger.info(f'Done refreshing files in {directory}')
|
||||
|
||||
|
||||
def file_search(search_str: str, limit: int, offset: int, mimetype: str = None, model: str = None) -> Tuple[
|
||||
List[dict], int]:
|
||||
def search_files(search_str: str, limit: int, offset: int, mimetype: str = None, model: str = None) -> \
|
||||
Tuple[List[dict], int]:
|
||||
"""
|
||||
Search the Files table. Order the returned Files by their rank if `search_str` is provided. Return all files if
|
||||
`search_str` is empty.
|
||||
|
|
@ -342,6 +342,11 @@ def handle_search_results(statement: str, params):
|
|||
return [], 0
|
||||
total = results[0]['total'] if results else 0
|
||||
ranked_paths = [pathlib.Path(i['path']) for i in results]
|
||||
try:
|
||||
ranks = [i['ts_rank'] for i in results]
|
||||
except KeyError:
|
||||
# No `ts_rank`, probably not searching `file.textsearch`.
|
||||
ranks = []
|
||||
|
||||
with get_db_session() as session:
|
||||
results = get_ranked_models(ranked_paths, File, session=session)
|
||||
|
|
@ -352,6 +357,9 @@ def handle_search_results(statement: str, params):
|
|||
if PYTEST:
|
||||
raise
|
||||
results = [i.__json__() for i in results]
|
||||
# Preserve the ts_ranks, if any.
|
||||
for idx, rank in enumerate(ranks):
|
||||
results[idx]['ts_rank'] = rank
|
||||
|
||||
return results, total
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class File(ModelHelper, Base):
|
|||
path = str(self.path.relative_to(get_media_directory()))
|
||||
return f'<File {path=} mime={self.mimetype} model={self.model}>'
|
||||
|
||||
def __json__(self):
|
||||
def __json__(self) -> dict:
|
||||
path = self.path.relative_to(get_media_directory())
|
||||
d = dict(
|
||||
associated=self.associated,
|
||||
|
|
|
|||
|
|
@ -326,17 +326,17 @@ async def test_files_indexer(test_session, make_files_structure):
|
|||
assert video_file.suffix == '.mp4'
|
||||
|
||||
# File are indexed by their titles and contents.
|
||||
files, total = lib.file_search('file', 10, 0)
|
||||
files, total = lib.search_files('file', 10, 0)
|
||||
assert total == 7, 'All files contain "file" in their file name. The associated video file is hidden.'
|
||||
files, total = lib.file_search('image', 10, 0)
|
||||
files, total = lib.search_files('image', 10, 0)
|
||||
assert total == 1 and files[0]['title'] == 'an image file.jpeg', 'The image file title contains "image".'
|
||||
files, total = lib.file_search('contents', 10, 0)
|
||||
files, total = lib.search_files('contents', 10, 0)
|
||||
assert total == 1 and files[0]['title'] == 'a text file.txt', 'The text file contains "contents".'
|
||||
files, total = lib.file_search('video', 10, 0)
|
||||
files, total = lib.search_files('video', 10, 0)
|
||||
assert total == 1 and {i['title'] for i in files} == {'a video file.mp4'}, 'The video file contains "video".'
|
||||
files, total = lib.file_search('yawn', 10, 0)
|
||||
files, total = lib.search_files('yawn', 10, 0)
|
||||
assert total == 1 and files[0]['title'] == 'a video file.mp4', 'The video file captions contain "yawn".'
|
||||
files, total = lib.file_search('bunny', 10, 0)
|
||||
files, total = lib.search_files('bunny', 10, 0)
|
||||
assert total == 3 and {i['title'] for i in files} == {'a zip file.zip', 'a bzip file.bzip', 'a gzip file.gzip'}, \
|
||||
'The zip files contain a file with "bunny" in the title.'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue