diff options
| author | Hunternif <hunternif@gmail.com> | 2021-09-02 04:01:40 +0100 |
|---|---|---|
| committer | Hunternif <hunternif@gmail.com> | 2021-09-02 04:01:40 +0100 |
| commit | 6ddc41347bae13a05005a7b8511257d92d04d8c1 (patch) | |
| tree | da55ed5243185097fb0062f3cf52fbc451220cb0 /server | |
| parent | 89d2885327f4c2080edc1e4115dd592a7220d071 (diff) | |
server: implement similar posts as a search term, without sort
Diffstat (limited to 'server')
| -rw-r--r-- | server/szurubooru/search/configs/post_search_config.py | 26 | ||||
| -rw-r--r-- | server/szurubooru/tests/search/configs/test_post_search_config.py | 33 |
2 files changed, 59 insertions, 0 deletions
diff --git a/server/szurubooru/search/configs/post_search_config.py b/server/szurubooru/search/configs/post_search_config.py index eda4084..c8eed18 100644 --- a/server/szurubooru/search/configs/post_search_config.py +++ b/server/szurubooru/search/configs/post_search_config.py @@ -122,6 +122,31 @@ def _pool_filter( )(query, criterion, negated) +# includes the given post itself +def _similar_filter( + query: SaQuery, criterion: Optional[criteria.BaseCriterion], negated: bool +) -> SaQuery: + assert criterion + # subquery for tags of the given post (post id in criterion) + filter_func_tag = search_util.create_num_filter(model.PostTag.post_id) + tag_query = db.session.query(model.PostTag.tag_id) + tag_query = filter_func_tag(tag_query, criterion, False) + tag_query = tag_query.subquery("source_tags") + + # subquery for posts with matching tags + pt_alias = sa.orm.aliased(model.PostTag) + subquery = ( + db.session.query(pt_alias.post_id) + .filter(pt_alias.tag_id.in_(tag_query)) + .group_by(pt_alias.post_id) + .subquery("similar_posts") + ) + expr = model.Post.post_id.in_(subquery) + if negated: + expr = ~expr + return query.filter(expr) + + def _create_metric_num_filter(name: str): def wrapper( query: SaQuery, @@ -414,6 +439,7 @@ class PostSearchConfig(BaseSearchConfig): ), ), (["pool"], _pool_filter), + (["similar"], _similar_filter), ] )) return filters diff --git a/server/szurubooru/tests/search/configs/test_post_search_config.py b/server/szurubooru/tests/search/configs/test_post_search_config.py index 84e1601..3a347de 100644 --- a/server/szurubooru/tests/search/configs/test_post_search_config.py +++ b/server/szurubooru/tests/search/configs/test_post_search_config.py @@ -965,3 +965,36 @@ def test_around_query( db.session.add_all([tag_a, tag_b, tag_c, post1, post2, post3]) db.session.flush() verify_around(input, 2, expected_prev_id, expected_next_id) + + +@pytest.mark.parametrize("input,expected_post_ids", [ + ("similar:1", [6, 4, 1]), + ("similar:2", [6, 5, 4, 2]), + ("similar:3", [6, 5, 3]), + ("similar:4", [6, 5, 4, 2, 1]), + ("similar:5", [6, 5, 4, 3, 2]), + ("similar:6", [6, 5, 4, 3, 2, 1]), + ("-similar:1", [5, 3, 2]), + ("-similar:2", [3, 1]), + ("-similar:3", [4, 2, 1]), + ("-similar:4", [3]), + ("-similar:5", [1]), + ("-similar:6", []), +]) +def test_filter_by_similar( + post_factory, tag_factory, verify_unpaged, input, expected_post_ids +): + tagA = tag_factory(names=["a"]) + tagB = tag_factory(names=["b"]) + tagC = tag_factory(names=["c"]) + postA = post_factory(id=1, tags=[tagA]) + postB = post_factory(id=2, tags=[tagB]) + postC = post_factory(id=3, tags=[tagC]) + postAB = post_factory(id=4, tags=[tagA, tagB]) + postBC = post_factory(id=5, tags=[tagB, tagC]) + postABC = post_factory(id=6, tags=[tagA, tagB, tagC]) + db.session.add_all( + [tagA, tagB, tagC, postA, postB, postC, postAB, postBC, postABC] + ) + db.session.flush() + verify_unpaged(input, expected_post_ids, True) |