diff options
| author | Hunternif <hunternif@gmail.com> | 2021-09-02 04:11:09 +0100 |
|---|---|---|
| committer | Hunternif <hunternif@gmail.com> | 2021-09-02 04:11:09 +0100 |
| commit | 05a1221591b287e482d0c63d89b04b57d18d4228 (patch) | |
| tree | 9774444af3fbccced7f7276b3291d525509be33f | |
| parent | 6ddc41347bae13a05005a7b8511257d92d04d8c1 (diff) | |
server: search term similar posts applies sort automatically
| -rw-r--r-- | server/szurubooru/search/configs/post_search_config.py | 37 | ||||
| -rw-r--r-- | server/szurubooru/tests/search/configs/test_post_search_config.py | 27 |
2 files changed, 50 insertions, 14 deletions
diff --git a/server/szurubooru/search/configs/post_search_config.py b/server/szurubooru/search/configs/post_search_config.py index c8eed18..4b2c8bb 100644 --- a/server/szurubooru/search/configs/post_search_config.py +++ b/server/szurubooru/search/configs/post_search_config.py @@ -122,29 +122,40 @@ def _pool_filter( )(query, criterion, negated) -# includes the given post itself +# includes the given post itself, also applies sort 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) + pt_alias = sa.orm.aliased(model.PostTag) + + # subquery for tags of the given post (post id in criterion) 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) + # negated query runs normally, doesn't apply sort + 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) + return query.filter(~expr) + else: + # direct query applies sort + subquery = query.subquery("main_query") + return ( + db.session.query(model.Post) + .join(pt_alias, pt_alias.post_id == model.Post.post_id) + .filter(pt_alias.tag_id.in_(tag_query)) + .group_by(model.Post.post_id) + .join(subquery, pt_alias.post_id == subquery.c.id) + .order_by(sa.func.count(pt_alias.tag_id).desc()) + ) def _create_metric_num_filter(name: str): 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 3a347de..c9f2408 100644 --- a/server/szurubooru/tests/search/configs/test_post_search_config.py +++ b/server/szurubooru/tests/search/configs/test_post_search_config.py @@ -971,7 +971,7 @@ def test_around_query( ("similar:1", [6, 4, 1]), ("similar:2", [6, 5, 4, 2]), ("similar:3", [6, 5, 3]), - ("similar:4", [6, 5, 4, 2, 1]), + ("similar:4", [6, 4, 5, 2, 1]), ("similar:5", [6, 5, 4, 3, 2]), ("similar:6", [6, 5, 4, 3, 2, 1]), ("-similar:1", [5, 3, 2]), @@ -980,6 +980,9 @@ def test_around_query( ("-similar:4", [3]), ("-similar:5", [1]), ("-similar:6", []), + ("similar:4 sort:id,asc", [4, 6, 1, 2, 5]), + ("similar:4 b", [6, 4, 5, 2]), + ("similar:4 c", [6, 5]), ]) def test_filter_by_similar( post_factory, tag_factory, verify_unpaged, input, expected_post_ids @@ -998,3 +1001,25 @@ def test_filter_by_similar( ) db.session.flush() verify_unpaged(input, expected_post_ids, True) + + + +@pytest.mark.parametrize("input,expected_post_ids", [ + ("similar:1", [3, 1, 2]), + ("similar:2", [3, 2, 1]), + ("similar:3", [3, 1, 2]), +]) +def test_sort_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"]) + postAB = post_factory(id=1, tags=[tagA, tagB]) + postA = post_factory(id=2, tags=[tagA]) + postABC = post_factory(id=3, tags=[tagA, tagB, tagC]) + db.session.add_all( + [tagA, tagB, tagC, postA,postAB, postABC] + ) + db.session.flush() + verify_unpaged(input, expected_post_ids, True) |