在指定类别中搜索对象。 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
);
有一个产品 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
);