面向属性的搜索是帮助在大量数据中找到目标信息并提升所有类型应用程序用户搜索体验的重要功能。在本教程中,我们将了解什么是面向属性的搜索以及如何创建一个简单的实现。
面向属性的搜索与 自动补全 、拼写校正和搜索关键词高亮一样,是现代搜索应用的重要功能。特别是在电子商务产品中。
当处理大量数据和各种相关属性(如尺寸、颜色、制造商或其他内容)时,面向属性的搜索会派上用场。在查询大量数据时,搜索结果通常会包含大量不符合用户预期的条目。面向属性的搜索允许最终用户明确指定他们希望搜索结果满足的维度。
简单来说,它赋予用户通过搜索项的属性对搜索结果进行过滤的能力。
假设用户想查找一些由尼古拉斯·凯奇主演的电影,他会将名字输入搜索栏。这将返回不同年份、不同导演、不同IMDB评分和评级的电影搜索结果。
这可能看起来像这样:
我们可以看到用户有34部不同年份的电影,但如何从如此庞大的数量中选择一部观看呢?
这时面向属性的搜索就派上用场了。我们可以让用户通过选择额外参数(如“年份”、“评分”、“导演姓名”和“IMDB评分”等)来找到他想看的电影。
面向属性的搜索结果将如下所示:
通过面向属性的搜索,我们可以确定用户到底想要什么。通过选择属性,用户可以获得更多相关的搜索结果,从而在用户体验和商业目标方面使搜索更加高效、便捷和实用。
那么,让我们看看面向属性的搜索是如何工作的,以及如何为您的搜索应用自己实现它。
实现电影的面向属性搜索
在Manticore Search中,有一种优化方法可以保留原始查询的结果集,并将其用于每个属性计算。由于聚合操作应用于已经计算出的文档子集,因此它们执行得很快,总执行时间在许多情况下仅比初始查询略高。属性可以添加到任何查询中,属性可以是任何属性或表达式。属性结果包含属性值和属性计数。可以通过 SQL SELECT 语句使用属性,通过在查询的最后声明它们,格式如下:
FACET {expr_list} [BY {expr_list}] [ORDER BY {expr | FACET()} {ASC | DESC}] [LIMIT [offset,] count]
当然,您可以在单个 multi-query 中发送所有想要的查询,但如果您正在寻找更优雅的解决方案,可以使用FACET子句。
现在,我们将运行几个带有电影属性的查询,例如:
- Title_year
- Content_rating
- Director_name
并使用 interval 来获取IMDB评分的整数范围内的值。
让我们在自动补全课程中的'movies'索引上尝试一些简单的属性,并对几个属性执行简单的属性过滤。例如,从“导演姓名”属性中选择“robert de niro”。
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 10 FACET title_year FACET content_rating FACET director_name;
这会返回多个结果集,其中第一个是我们的主查询结果,其余的是属性。每个属性结果包含属性值和分组计数。
+------------+----------+
| title_year | count(*) |
+------------+----------+
| 1987 | 1 |
| 1991 | 1 |
| 2005 | 1 |
| 1997 | 3 |
| 1974 | 1 |
| 2001 | 2 |
| 2002 | 2 |
| 1999 | 2 |
| 1985 | 1 |
| 1995 | 1 |
| 2016 | 2 |
| 2009 | 1 |
| 2004 | 4 |
| 1990 | 1 |
| 2013 | 3 |
| 2015 | 3 |
| 2011 | 2 |
| 2010 | 3 |
| 1996 | 3 |
| 1973 | 1 |
+------------+----------+
20 rows in set (0.10 sec)
+----------------+----------+
| content_rating | count(*) |
+----------------+----------+
| R | 37 |
| PG-13 | 12 |
| PG | 4 |
+----------------+----------+
3 rows in set (0.10 sec)
+----------------------+----------+
| director_name | count(*) |
+----------------------+----------+
| Brian De Palma | 1 |
| Martin Scorsese | 7 |
| John Polson | 1 |
| Quentin Tarantino | 1 |
| Francis Ford Coppola | 1 |
| John Herzfeld | 1 |
| Harold Ramis | 2 |
| Terry Gilliam | 1 |
| Michael Caton-Jones | 1 |
| James Mangold | 1 |
| Dan Mazer | 1 |
| Kirk Jones | 1 |
| Joel Schumacher | 1 |
| Nick Hamm | 1 |
| Peter Segal | 1 |
| Jonathan Jakubowicz | 1 |
| Scott Mann | 1 |
| David O. Russell | 2 |
| Gary McKendry | 1 |
| Jon Turteltaub | 1 |
+----------------------+----------+
20 rows in set (0.10 sec)
FACETS中的排序
默认情况下,属性结果不会排序,且限制为20行。每个属性可以有自己的限制子句。可以这样实现:
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 10 FACET title_year LIMIT 5 FACET content_rating LIMIT 1 FACET director_name LIMIT 100;
+------------+----------+
| title_year | count(*) |
+------------+----------+
| 1987 | 1 |
| 1991 | 1 |
| 2005 | 1 |
| 1997 | 3 |
| 1974 | 1 |
+------------+----------+
5 rows in set (0.19 sec)
+----------------+----------+
| content_rating | count(*) |
+----------------+----------+
| R | 37 |
+----------------+----------+
1 row in set (0.19 sec)
+----------------------+----------+
| director_name | count(*) |
+----------------------+----------+
| Brian De Palma | 1 |
| Martin Scorsese | 7 |
| John Polson | 1 |
| Quentin Tarantino | 1 |
| Francis Ford Coppola | 1 |
.................................
| Tony Scott | 1 |
| Nancy Meyers | 1 |
| Frank Oz | 1 |
| Neil Jordan | 1 |
+----------------------+----------+
42 rows in set (0.19 sec)
如您所见,默认情况下结果不会排序。每个属性可以有自己的排序规则,例如,我们可以使用COUNT(*)按计数对分组进行排序:
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 10 FACET title_year ORDER BY COUNT(*) DESC;
+------------+----------+
| title_year | count(*) |
+------------+----------+
| 2004 | 4 |
| 2013 | 3 |
| 2015 | 3 |
| 1997 | 3 |
| 2010 | 3 |
| 1996 | 3 |
| 2000 | 3 |
| 2001 | 2 |
| 2002 | 2 |
| 1999 | 2 |
| 2016 | 2 |
| 2011 | 2 |
| 2012 | 2 |
| 2008 | 2 |
| 1985 | 1 |
| 1991 | 1 |
| 1995 | 1 |
| 2009 | 1 |
| 1990 | 1 |
| 2005 | 1 |
+------------+----------+
20 rows in set (0.09 sec)
或者,我们可以按属性排序,例如title_year:
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 10 FACET title_year ORDER BY title_year DESC;
+------------+----------+
| title_year | count(*) |
+------------+----------+
| 2016 | 2 |
| 2015 | 3 |
| 2013 | 3 |
| 2012 | 2 |
| 2011 | 2 |
| 2010 | 3 |
| 2009 | 1 |
| 2008 | 2 |
| 2005 | 1 |
| 2004 | 4 |
| 2002 | 2 |
| 2001 | 2 |
| 2000 | 3 |
| 1999 | 2 |
| 1998 | 1 |
| 1997 | 3 |
| 1996 | 3 |
| 1995 | 1 |
| 1991 | 1 |
| 1990 | 1 |
+------------+----------+
20 rows in set (0.09 sec)
属性选择
在最简单的示例中,我们使用FACET attr_name,结果集将包含attr_name和count列。
但属性可以由多个属性组成:
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 10 FACET director_facebook_likes,director_name BY director_name ORDER BY director_facebook_likes DESC;
+-------------------------+---------------------+----------+
| director_facebook_likes | director_name | count(*) |
+-------------------------+---------------------+----------+
| 17000 | Martin Scorsese | 7 |
| 16000 | Quentin Tarantino | 1 |
| 12000 | Tony Scott | 1 |
| 11000 | Harold Ramis | 2 |
| 737 | David O. Russell | 2 |
| 541 | Joel Schumacher | 1 |
| 517 | Michael Cimino | 1 |
| 446 | James Mangold | 1 |
| 287 | John Frankenheimer | 1 |
| 278 | Nancy Meyers | 1 |
| 277 | Neil Jordan | 1 |
| 272 | Barry Levinson | 3 |
| 226 | Jon Turteltaub | 1 |
| 116 | Jay Roach | 2 |
| 105 | Michael Caton-Jones | 1 |
| 102 | Martin Brest | 1 |
| 89 | Rodrigo Cortés | 1 |
| 88 | Peter Segal | 1 |
| 88 | George Tillman Jr. | 1 |
| 80 | Paul Weitz | 1 |
+-------------------------+---------------------+----------+
20 rows in set (0.01 sec)
FACET中的表达式
在某些情况下,我们不希望对实际值进行属性过滤。最常见的例子是产品价格,因为我们可以有广泛的价格范围。与其获取实际值的属性,我们更希望获取一个范围列表。这可以通过函数INTERVAL()轻松实现。
在我们的示例中,我们使用imdb_score,因为它是一个浮点值,显然我们不想按其分组,而是按仅整数值之间的范围进行分组:
SELECT * FROM movies WHERE MATCH('robert de niro') LIMIT 100 FACET title_year LIMIT 100 FACET content_rating LIMIT 100 FACET director_name LIMIT 100;
Empty set (0.09 sec)
+------------+----------+
| title_year | count(*) |
+------------+----------+
| 1987 | 1 |
| 1991 | 1 |
| 2005 | 1 |
| 1997 | 3 |
| 1974 | 1 |
| 2001 | 2 |
| 2002 | 2 |
| 1999 | 2 |
| 1985 | 1 |
| 1995 | 1 |
| 2016 | 2 |
| 2009 | 1 |
| 2004 | 4 |
| 1990 | 1 |
| 2013 | 3 |
| 2015 | 3 |
| 2011 | 2 |
| 2010 | 3 |
| 1996 | 3 |
| 1973 | 1 |
| 2000 | 3 |
| 1988 | 1 |
| 1977 | 1 |
| 1984 | 1 |
| 1980 | 1 |
| 2012 | 2 |
| 2008 | 2 |
| 1998 | 1 |
| 1976 | 1 |
| 1978 | 1 |
| 1989 | 1 |
+------------+----------+
31 rows in set (0.07 sec)
+----------------+----------+
| content_rating | count(*) |
+----------------+----------+
| R | 37 |
| PG-13 | 12 |
| PG | 4 |
+----------------+----------+
3 rows in set (0.08 sec)
+----------------------+----------+
| director_name | count(*) |
+----------------------+----------+
| Brian De Palma | 1 |
| Martin Scorsese | 7 |
| John Polson | 1 |
| Quentin Tarantino | 1 |
| Francis Ford Coppola | 1 |
| John Herzfeld | 1 |
| Harold Ramis | 2 |
| Terry Gilliam | 1 |
| Michael Caton-Jones | 1 |
| James Mangold | 1 |
| Dan Mazer | 1 |
| Kirk Jones | 1 |
| Joel Schumacher | 1 |
| Nick Hamm | 1 |
| Peter Segal | 1 |
| Jonathan Jakubowicz | 1 |
| Scott Mann | 1 |
| David O. Russell | 2 |
| Gary McKendry | 1 |
| Jon Turteltaub | 1 |
| Paul Weitz | 1 |
| Ethan Maniquis | 1 |
| Jerry Zaks | 1 |
| Jay Roach | 2 |
| George Tillman Jr. | 1 |
| Martin Brest | 1 |
| Garry Marshall | 1 |
| Sergio Leone | 1 |
| Rodrigo Cortés | 1 |
| Jon Avnet | 1 |
| John Frankenheimer | 1 |
| Bibo Bergeron | 1 |
| Barry Levinson | 3 |
| John Curran | 1 |
| Des McAnuff | 1 |
| Justin Zackham | 1 |
| Mary McGuckian | 1 |
| Michael Cimino | 1 |
| Tony Scott | 1 |
| Nancy Meyers | 1 |
| Frank Oz | 1 |
| Neil Jordan | 1 |
+----------------------+----------+
42 rows in set (0.08 sec)
<img src="Faceted-search-course-example-optimized.webp" alt="img">
交互式课程
如果您参加我们的免费“Manticore属性过滤”交互式课程,可以了解更多关于面向属性搜索的内容,该课程包含命令行和网页面板,便于学习。
