搜索最佳实践

本文档介绍了 Search API 的最佳实践。在本文中,我们通篇使用英文单引号 ('') 来分隔查询字符串。这样,我们可以分隔包含由英文双引号引起来的多词短语的查询,而不致混淆:'field:"some text" some-value'

批量 Index.put() 和 Index.delete() 调用

在向索引中添加或从中删除文档时,一次最多可以传递 200 个文档。这比一次处理一个文档更有效。

使用文档排名对文档进行预排序

默认情况下,搜索按照降序返回结果。此外,默认情况下,自 2011 年 1 月 1 日起,Search API 将每个文档的排名设置为按时间排序,以秒为单位。这将导致首先返回最新的文档。不过,如果不需要按照添加时间为文档排序,您可以将排名用于其他目的。假设您有一个房地产应用。客户最想获得的是按价格排序的结果。为获得有效的默认排序,您可以将排名设置为房价。

如果您需要多个排序(如价格从低到高和价格从高到低),则可以为每种顺序创建单独索引。一个索引可以设置 rank = price,另一个可以设置 rank = MAXINT-price(因为排名必须为正数)。

把排名用作排序键,将改善搜索效果。要指定其他排序键,则必须使用排序选项,将搜索结果的数量限制为 10,000 个文档。在这种情况下,按排名确定的排序将确定排序中将包含哪些文档。如需了解详情,请参阅排序选项

将 atom 字段用于布尔值数据

在数字字段中存储布尔值数据效率非常低下。建议改为使用 atom 字段,并分配您喜爱的常量(True/False、是/否、0/1)。

将否定变为肯定

假设您有一个专用词用于识别菜系未知的餐厅。如果想排除这些餐厅,您可以在查询中使用 ‘NOT cuisine:undefined’。然而,这种评估方法比查找已定义菜系的餐厅更不划算(在计费操作和计算时间方面)。相对于使用 cuisine 一个字段,您可以使用 cuisinecuisine_known 两个字段,其中后者是一个 atom 字段。对于已定义菜系的餐厅,请将第一个字段设置为实际菜系,第二个字段设置为 "yes"。对于您不了解其菜系的餐厅,您可以将 cuisine 设置为 ""(空字符串),然后将 cuisine_known 设置为 "no"。现在,要查找菜系已知的餐厅,您可以发出一个查询 ‘cuisine_known:yes’,这比否定要快得多。

将析取变为合取

“OR”析取操作在可计费操作和计算时间中均成本高昂。假设您要搜索 ‘cuisine:Japanese OR cuisine:Korean’。您可以选择按照更宽泛的菜系类别为文档编索引。在这种情况下,查询可以简化为 ‘cuisine:Asian’

消除查询中的同义反复

假设您要查找多伦多的所有餐厅。假定您的文档只有一个名为“city”的单个字段,那么当您使用查询 ‘city:toronto AND NOT city:montreal’ 时,将获取与 ‘city:toronto’ 一样的结果,因为当 city 设置为 "toronto" 时,其无法设置为 "montreal"。第二个查询运行得更快,因为它只涉及一个字词。第一个查询执行三个步骤:首先,它找到“city”设置为“toronto”的文档列表,然后找到“city”未设置为“montreal”的所有城市的列表,最后计算这两个列表的重叠部分。

在排序前缩小范围

假设您的应用存储有关世界各地餐厅的信息,并且您想显示离当前用户最近的餐厅。一种方法是按照餐厅与用户所在位置的距离对匹配的文档进行排序。但是,如果有一百万家餐厅,那么使用排序表达式 distance(geopoint(x, y), restaurant_loc) 运行像 ‘cuisine:japanese’ 这样的查询会花费很长时间。建议的做法是向查询添加过滤条件,使您的排序对象缩小为一组更明确的选定文档。一种解决方案是创建地理类别,例如国家、州和城市 - 您可以从用户的位置判断其所在城市和州。然后,您的查询就会变为 ‘cuisine:japanese AND city:<user-city>’。这样一来,您很可能就不需要再为一百万个文档进行排序了。

使用狭义类别来避免或减少排序

如果您使用排名按价格对餐厅进行排序,则可以创建一个 price_range 字段,其中包含价格类别:price_0_10price_11_20price_21_30price_31_40price_41_lots。然后,您可以使用查询 ‘price_range:price_21_30 OR price_range:price_31_40’ 查找价格在 $21 到 $40 之间的所有餐厅,而不进行任何排序。在许多情况下,合适的类别并不那么明确,但通过这种方式可以先排除掉大量文档,然后再使用成本高昂的查询(例如 ‘... AND price>25 AND price<35’)筛选搜索结果。

除非需要,否则不对匹配程度进行评分

评分用于表示指定文档与查询相匹配的程度。不过,除非您打算按评分排序,否则请勿进行评分。因为这只会减慢您的搜索速度。