Elasticsearch: Terms lookup查询方案
场景:商品池索引 sku_data,需要过滤编码字段skuCode
Terms
使用terms查询商品编码
{ "query": { "bool": { "filter": [ { "terms": { "skuCode": [ "7700220626", "7700159221" ] } } ] } } }
terms查询字词限制为65535,上面的查询参数skuCode是静态参数,如果要从其他索引动态传入,可以使用 Terms lookup
Terms lookup
参数:
index
(必需,字符串)从中获取字段值的索引的名称。
id
(必需,字符串)要从中获取字段值的文档的ID。
path
(必需,字符串)要从中获取字段值的字段名称。 Elasticsearch 使用这些值作为查询的搜索词。 如果字段值包含嵌套的内部对象的数组,则可以使用点表示法语法访问这些对象。
routing
(可选,字符串)从中获取术语值的文档的自定义路由值。 如果在为文档建立索引时提供了自定义路由值,则此参数是必需的。
例子
用户拥有的商品索引user_skus
用户id=10000的文档
{ "_index" : "user_skus", "_type" : "_doc", "_id" : "10000", "_score" : 1.0, "_source" : { "skus" : [ "1401027979", "1401027980", "1401027978", "1401027981" ] } } }
使用Terms lookup筛选skuCode字段,此查询将中user_skus索引,文档id10000,skus字段的商品作为参数传入terms的数组
GET sku_data/_search
{ "query": { "bool": { "filter": [ { "terms": { "skuCode": { "index": "user_skus", "id": "10000", "path": "skus" } } } ] } } }
Terms lookup也有查询字词限制,限制65535。可以修改动态参数index.max_terms_count来提高限制,但会影响查询效率。(公司项目中30万字词查询了3秒)
修改terms参数语句
PUT sku_data/_settings { "index.max_terms_count": 500000 }
同步数据时一个请求无法添加几十万条商品数据,需要拆分商品,发送多次请求追加商品
添加商品
POST user_skus/_doc/10000 { "skus": [ "1401027979", "1401027980" ] }
但再次请求会覆盖掉skus字段,不会追加。想要给skus数组增加元素需要使用script脚本
Script
文档id=10000,字段skus数组添加元素
POST user_skus/_doc/10000/_update { "script":{ "inline": "ctx._source.skus.addAll(params.new_tag)", "params" : { "new_tag" : ["110022","55280"] } } }
添加后的元素为
"_source" : { "skus" : [ "1401027979", "1401027980", "110022", "55280"
] }
Java实现
Terms lookup查询
1 public SearchResponse termsLookUpSearch() throws IOException { 2 SearchRequest searchRequest = new SearchRequest("sku_data"); 3 BoolQueryBuilder boolQuery = new BoolQueryBuilder(); 4 String index = "user_skus"; 5 String id = "100000"; 6 String path = "skus"; 7 boolQuery.filter(QueryBuilders.termsLookupQuery("skuCode", new TermsLookup(index, id, path))); 8 SearchSourceBuilder source = SearchSourceBuilder.searchSource(); 9 source.query(boolQuery); 10 searchRequest.source(source); 11 return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); 12 }
Script脚本更新文档
/** * 多个文档增加skus字段 * @param dataMap * { * "10000": ["1102552","11023658","112562"], * "10002": ["7745211","7742562"] * } */ public void addUserSkus(Map<String, List<String>> dataMap) { String userSkusIndex = "user_skus"; BulkRequest bulkRequest = new BulkRequest(); for (Map.Entry<String, List<String>> entry : dataMap.entrySet()) { //没有文档则新增 IndexRequest index = new IndexRequest(userSkusIndex); index.id(entry.getKey()); Map<String, Object> map = new HashedMap<>(); map.put("skus", entry.getValue()); index.source(map); //修改使用script脚本 UpdateRequest update = new UpdateRequest(userSkusIndex, entry.getKey()); Map<String, Object> params = new HashedMap<>(); params.put("new_tag", entry.getValue()); Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "ctx._source.skus.addAll(params.new_tag)", params); update.script(script); //新增或修改 update.upsert(index); bulkRequest.add(update); } try { BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } }
*为保护使用者隐私,以上引用索引均采用化名
参考文档:
https://elasticstack.blog.csdn.net/article/details/112857984