如何用algolia/scout-extended实现动态分面及数值过滤?
实现方案及分面适用性说明
分面属性是否适用?
分面属性主要用于等值过滤、数值区间筛选(比如生成侧边栏的可选范围选项),但有明确局限性:
- 单个字段的
>/<比较:可以配合分面的范围逻辑生成筛选选项,但实际执行过滤更推荐直接用数值过滤器,分面只是辅助展示筛选维度,不是核心过滤方式。 - 跨字段比较(比如
completed_tasks_count > active_tasks_count):分面完全不适用,因为分面基于单个字段的统计逻辑,无法实现跨字段的数值计算对比。
具体实现方法
1. 单个数值字段的比较(如active_tasks_count > 10)
前提是确保active_tasks_count在Algolia索引中被标记为数值类型(若同步时是字符串类型,需在模型或Algolia后台调整字段类型),有两种简洁实现方式:
方式一:使用Scout的where方法
// 无需全文搜索时,search参数传空字符串 $categories = Category::search('') ->where('active_tasks_count', '>', 10) ->get();
方式二:直接使用Algolia过滤表达式
$categories = Category::search('') ->filter('active_tasks_count > 10') ->get();
2. 跨字段数值比较(如completed_tasks_count > active_tasks_count)
这种场景无法通过分面实现,推荐两种方案:
方案一:提前计算虚拟字段(推荐,性能更优)
在Category模型的toSearchableArray方法中添加预计算的布尔字段,同步数据时直接生成结果:
public function toSearchableArray() { $array = $this->toArray(); // 原有计算字段 $array['active_tasks_count'] = $this->tasks()->where('status', 'active')->count(); $array['completed_tasks_count'] = $this->tasks()->where('status', 'completed')->count(); // 添加虚拟字段,标记是否已完成任务数大于活跃任务数 $array['is_completed_more_than_active'] = $array['completed_tasks_count'] > $array['active_tasks_count'] ? 1 : 0; return $array; }
之后过滤时直接匹配该字段:
$categories = Category::search('') ->where('is_completed_more_than_active', 1) ->get();
方案二:使用Algolia高级筛选表达式
如果不想预计算字段,可以直接在filter中写跨字段比较逻辑(需确保索引支持高级筛选,且两个字段均为数值类型):
$categories = Category::search('') ->filter('completed_tasks_count > active_tasks_count') ->get();
注意:该方式每次查询都会实时计算,性能略低于预计算字段的方案,适合动态调整比较逻辑的场景。
内容的提问来源于stack exchange,提问作者Petro Gromovo
相关产品推荐
相关产品推荐

