在指定类别中搜索对象。 HQL/MYSQL

Search for an object in the specified categories. HQL / MYSQL

有一个产品 table 具有多对多 link 类别。

我的目标是 select 给定类别的前 5 名最合适table 产品。

现在我已经实现了这样的查询,但是效果不是很好,因为一开始是按类目数匹配,然后是第一个匹配类目名称。

@Query("SELECT p FROM Product p JOIN p.categories c WHERE c.name IN (:categories) ORDER BY SIZE(p.categories) DESC")
    List<Product> findByCategories_NameInOrderByCount(@Param("categories") Collection<String> categories);

如何改进我的查询,使其成为第一个 return 类目匹配名称最多的产品?

你的查询是错误的,你应该使用类似这样的东西:

@Query("SELECT p FROM Product p WHERE (SELECT COUNT(*) FROM p.categories c WHERE c.name IN (:categories)) > 0 ORDER BY (SELECT COUNT(*) FROM p.categories c WHERE c.name IN (:categories)) DESC")
List<Product> findByCategories_NameInOrderByCount(@Param("categories") 
Collection<String> categories);

无论如何,这可能也不会执行得很好,因为数据库将不得不连接和排序三个 table。为避免这种情况,通常使用 MySQL 所称的倒排索引或多值索引 (https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-multi-valued)。删除 product_has_category 和类别 table,而是在产品 table.

中引入一个 JSON 列“详细信息”

然后您可以创建一个索引:

CREAT INDEX categories ON product( (CAST(JSON_EXTRACT(categories, '$[*]') AS VARCHAR(80) ARRAY)) )

然后这样查询:

@Query("SELECT p FROM Product p WHERE FUNCTION('JSON_OVERLAPS', FUNCTION('JSON_EXTRACT', p.categories, '$[*]'), :categories) = 1 ORDER BY FUNCTION('COUNT_MATCHES', p.categories, :categories) DESC")
List<Product> findByCategories_NameInOrderByCount(@Param("categories") 
String categories);

但是你需要给你的数据库添加一个函数:

CREATE FUNCTION COUNT_MATCHES (categories JSON, searchCategories JSON)
    RETURNS INT DETERMINISTIC
   RETURN (
     SELECT COUNT(*) 
     FROM JSON_TABLE(categories, '$[*]' COLUMNS(
       name VARCHAR(80) PATH '$' ERROR ON ERROR)
     ) c
     JOIN JSON_TABLE(searchCategories, '$[*]' COLUMNS(
       name VARCHAR(80) PATH '$' ERROR ON ERROR )
     ) s ON c.name = s.name
   );