使用统计聚合功能可以实现求最小值、求最大值、求和、求平均值、统计行数、去重统计行数、按字段值分组、按范围分组、按地理位置分组、按过滤条件分组等操作;同时多个统计聚合功能可以组合使用,满足复杂的查询需求。
流程
统计聚合的完整执行流程如下图所示。

统计聚合是在服务端的“查询”结束后执行,服务端会将“查询”阶段命中的所有文档根据查询请求进行统计聚合,因此统计聚合请求相比没有统计聚合的请求会复杂。
背景信息
功能 | 说明 |
---|---|
最小值 |
返回一个字段中的最小值,类似于SQL中的min。 |
最大值 |
返回一个字段中的最大值,类似于SQL中的max。 |
和 |
返回数值字段的总数,类似于SQL中的sum。 |
平均值 |
返回数值字段的平均值,类似于SQL中的avg。 |
统计行数 | 返回指定字段值的数量或者多元索引数据总行数,类似于SQL中的count。 |
去重统计行数 | 返回指定字段不同值的数量,类似于SQL中的count(distinct)。 |
百分位统计 |
百分位统计常用来统计一组数据的百分位分布情况,例如在日常系统运维中统计每次请求访问的耗时情况时,需要关注系统请求耗时的P25、P50、P90、P99值等分布情况。 |
字段值分组 |
根据一个字段的值对查询结果进行分组,相同的字段值放到同一分组内,返回每个分组的值和该值对应的个数。
说明 当分组较大时,按字段值分组可能会存在误差。
|
范围分组 |
根据一个字段的范围对查询结果进行分组,字段值在某范围内放到同一分组内,返回每个范围中相应的item个数。 |
地理位置分组 |
根据距离某一个中心点的范围对查询结果进行分组,距离差值在某范围内放到同一分组内,返回每个范围中相应的item个数。 |
过滤条件分组 |
按照过滤条件对查询结果进行分组,获取每个过滤条件匹配到的数量,返回结果的顺序和添加过滤条件的顺序一致。 |
直方图统计 |
按照指定数据间隔对查询结果进行分组,字段值在相同范围内放到同一分组内,返回每个分组的值和该值对应的个数。 |
获取统计聚合分组中的行 |
对查询结果进行分组后,获取每个分组内的一些行数据,可实现和MySQL中ANY_VALUE(field)类似的功能。 |
前提条件
最小值
返回一个字段中的最小值,类似于SQL中的min。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 missing 当某行数据中的字段为空时,字段值的默认值。
- 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "min_test", type: TableStore.AggregationType.AGG_MIN, body: { fieldName: "col_long", missing: 333, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
最大值
返回一个字段中的最大值,类似于SQL中的max。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 missing 当某行数据中的字段为空时,字段值的默认值。
- 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "max_test", type: TableStore.AggregationType.AGG_MAX, body: { fieldName: "col_long", missing: 333, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
和
返回数值字段的总数,类似于SQL中的sum。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 missing 当某行数据中的字段为空时,字段值的默认值。
- 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "sum_test", type: TableStore.AggregationType.AGG_SUM, body: { fieldName: "col_long", missing: 444, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
平均值
返回数值字段的平均值,类似于SQL中的avg。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 missing 当某行数据中的字段为空时,字段值的默认值。
- 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "avg_test", type: TableStore.AggregationType.AGG_AVG, body: { fieldName: "col_long", missing: 111, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
统计行数
- 使用统计聚合的count功能,在请求中设置count(*)。
- 使用query功能的匹配行数,在query中设置setGetTotalCount(true);如果需要统计多元索引数据总行数,则使用MatchAllQuery。
如果需要获取多元索引数据某列出现的次数,则使用count(列名),可应用于稀疏列的场景。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long、Double、Boolean、Keyword和Geo_point类型。 - 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "count_test", type: TableStore.AggregationType.AGG_COUNT, body: { fieldName: "col_long", }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
去重统计行数
- 当去重统计行数小于1万时,计算结果接近精确值。
- 当去重统计行数达到1亿时,计算结果的误差为2%左右。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long、Double、Boolean、Keyword和Geo_point类型。 missing 当某行数据中的字段为空时,字段值的默认值。 - 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "AGG_DISTINCT_COUNT_test", type: TableStore.AggregationType.AGG_DISTINCT_COUNT, body: { fieldName: "col_long", missing: 666, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
百分位统计
百分位统计常用来统计一组数据的百分位分布情况,例如在日常系统运维中统计每次请求访问的耗时情况时,需要关注系统请求耗时的P25、P50、P90、P99值等分布情况。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 percentiles 百分位分布例如50、90、99,可根据需要设置一个或者多个百分位。 missing 当某行数据中的字段为空时,字段值的默认值。 - 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, aggs: { aggs: [ { name: "AGG_PERCENTILES_test", type: TableStore.AggregationType.AGG_PERCENTILES, body: { fieldName: "col_long", percentiles: [20, 50, 90, 100], missing: 888, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
字段值分组
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long、Double、Boolean和Keyword类型。 sort 分组中的item排序规则,默认按照分组中item的数量降序排序,多个排序则按照添加的顺序进行排列。支持的参数如下。 - 按照值的字典序升序排列
- 按照值的字典序降序排列
- 按照行数升序排列
- 按照行数降序排列
- 按照子统计聚合结果中值升序排列
- 按照子统计聚合结果中值降序排列
size 返回的分组数量,最大值为2000。当分组数量超过2000时,只会返回前2000个分组。 subAggs和subGroupBys 子统计聚合,子统计聚合会根据分组内容再进行一次统计聚合分析。 - 场景
统计每个类别的商品数量,且统计每个类别价格的最大值和最小值。
- 方法
最外层的统计聚合是根据类别进行分组,再添加两个子统计聚合求价格的最大值和最小值。
- 结果示例
- 水果:5个(其中价格的最大值为15,最小值为3)
- 洗漱用品:10个(其中价格的最大值为98,最小值为1)
- 电子设备:3个(其中价格的最大值为8699,最小值为2300)
- 其它:15个(其中价格的最大值为1000,最小值为80)
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, groupBys: { groupBys: [ { name: "group_by_GROUP_BY_FIELD", type: TableStore.GroupByType.GROUP_BY_FIELD, body: { fieldName: "city", size: 111, sort: { sorters: [ { groupKeySort: { order: TableStore.SortOrder.SORT_ORDER_ASC, }, }, { rowCountSort: { order: TableStore.SortOrder.SORT_ORDER_DESC, }, }, ], }, subGroupBys: { // 嵌套子GroupBy。 groupBys: [ { name: "group_by_GROUP_BY_RANGE", type: TableStore.GroupByType.GROUP_BY_RANGE, body: { fieldName: "age", ranges: [ { from: 4, to: 5, }, { from: 6, to: 7, }, ], subAggs: { // 嵌套子Agg。 aggs: [ { name: "AGG_COUNT_test", type: TableStore.AggregationType.AGG_COUNT, body: { fieldName: "*", missing: 8, }, }, ], }, }, }, ], }, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
范围分组
根据一个字段的范围对查询结果进行分组,字段值在某范围内放到同一分组内,返回每个范围中相应的item个数。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 ranges[from, to) 分组的范围。 起始值from可以使用最小值Double.MIN_VALUE,结束值to可以使用最大值Double.MAX_VALUE。
subAggs和subGroupBys 子统计聚合,子统计聚合会根据分组内容再进行一次统计聚合分析。 例如按销量分组后再按省份分组,即可获得某个销量范围内哪个省比重比较大,实现方法是GroupByRange下添加一个GroupByField。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, groupBys: { groupBys: [ { name: "group_by_GROUP_BY_RANGE", type: TableStore.GroupByType.GROUP_BY_RANGE, body: { fieldName: "col_long", ranges: [ { from: 1, to: 5, }, { from: 3, to: 20, }, ], }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
地理位置分组
根据距离某一个中心点的范围对查询结果进行分组,距离差值在某范围内放到同一分组内,返回每个范围中相应的item个数。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Geo_point类型。 origin(lat, lon) 起始中心点的经纬度。 lat是起始中心点纬度,lon是起始中心点经度。
ranges[from, to) 分组的范围,单位为米。 起始值from可以使用最小值Double.MIN_VALUE,结束值to可以使用最大值Double.MAX_VALUE。
subAggs和subGroupBys 子统计聚合,子统计聚合会根据分组内容再进行一次统计聚合分析。 - 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, groupBys: { groupBys: [ { name: "group_by_GROUP_BY_GEO_DISTANCE", type: TableStore.GroupByType.GROUP_BY_GEO_DISTANCE, body: { fieldName: "col_geo", origin: { lat: 50, lon: 60, }, ranges: [ { from: 1, to: 2, }, { from: 3, }, ], }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
过滤条件分组
按照过滤条件对查询结果进行分组,获取每个过滤条件匹配到的数量,返回结果的顺序和添加过滤条件的顺序一致。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 filters 过滤条件,返回结果的顺序和添加过滤条件的顺序一致。 subAggs和subGroupBys 子统计聚合,子统计聚合会根据分组内容再进行一次统计聚合分析。 - 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, groupBys: { groupBys: [ { name: "group_by_GROUP_BY_FILTER", type: TableStore.GroupByType.GROUP_BY_FILTER, body: { filters: [ { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, { queryType: TableStore.QueryType.WILDCARD_QUERY, query: { fieldName: "col_keyword", value: "1*" }, }, ], }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
直方图统计
按照指定数据间隔对查询结果进行分组,字段值在相同范围内放到同一分组内,返回每个分组的值和该值对应的个数。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 fieldName 用于统计聚合的字段,仅支持Long和Double类型。 interval 统计间隔。 fieldRange[min,max] 统计范围,与interval参数配合使用限制分组的数量。 (fieldRange.max-fieldRange.min)/interval
的值不能超过2000。minDocCount 最小行数。当分组中的行数小于最小行数时,不会返回此分组的统计结果。 missing 当某行数据中的字段为空时,字段值的默认值。 - 如果未设置missing值,则在统计聚合时会忽略该行。
- 如果设置了missing值,则使用missing值作为字段值的默认值参与统计聚合。
- 示例
let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: false, groupBys: { groupBys: [ { name: "group_by_GROUP_BY_HISTOGRAM", type: TableStore.GroupByType.GROUP_BY_HISTOGRAM, body: { fieldName: "col_long", interval: Long.fromNumber(3), missing: Long.fromNumber(123), minDocCount: 5, fieldRange: { min: Long.fromNumber(1), max: Long.fromNumber(999), }, sort: { sorters: [ { groupKeySort: { order: TableStore.SortOrder.SORT_ORDER_ASC, }, }, { rowCountSort: { order: TableStore.SortOrder.SORT_ORDER_ASC, }, }, ], }, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: {返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });
获取统计聚合分组中的行
对查询结果进行分组后,获取每个分组内的一些行数据,可实现和MySQL中ANY_VALUE(field)类似的功能。
- 参数
参数 说明 name 自定义的统计聚合名称,用于区分不同的统计聚合,可根据此名称获取本次统计聚合结果。 limit 每个分组内最多返回的数据行数,默认返回1行数据。 sort 分组内数据的排序方式。 columnsToGet 指定返回的字段,仅支持多元索引中的字段,且不支持数组、Date、Geopoint和Nested类型的字段。 该参数复用SearchRequest中的columnsToGet参数,在SearchRequest中指定columnsToGet即可。
- 示例
某学校有一个活动报名表,活动报名表中包含学生姓名、班级、班主任、班长等信息,如果希望按班级进行分组,以查看每个班级的报名情况,同时获取班级的属性信息。等效的SQL语句是
select className, ANY_VALUE(teacher), ANY_VALUE(monitor), COUNT(*) as number from table GROUP BY className
。let searchQuery = { offset: 0, limit: 0, query: { queryType: TableStore.QueryType.MATCH_ALL_QUERY, }, getTotalCount: true, groupBys: { groupBys: [ { name: "group_by_name_xxx", type: TableStore.GroupByType.GROUP_BY_FIELD, body: { fieldName: "className", size: 200, subAggs: { aggs: [ { name: "top_row_name_xxx", type: TableStore.AggregationType.AGG_TOP_ROWS, body: { limit: 1, sort: { sorters: [ { fieldSort: { fieldName: "teacher", order: TableStore.SortOrder.SORT_ORDER_DESC, }, }, ], }, }, }, ], }, }, }, ], }, }; let params = { tableName: tableName, indexName: indexName, searchQuery: searchQuery, columnToGet: { //返回列设置,可设置为RETURN_SPECIFIED(自定义返回列)、RETURN_ALL(返回所有列)、RETURN_ALL_FROM_INDEX(返回多元索引中的所有列)、RETURN_NONE(不返回)。 returnType: TableStore.ColumnReturnType.RETURN_ALL_FROM_INDEX }, timeoutMs: 30000, } client.search(params, function (err, data) { if (err) { console.log('search error:', err.toString()); } else { console.log('search success:', data); } });