Elasticsearch搜索二、high-level-client使用搜索模板

586 阅读1分钟

遇到问题描述

  1. 使用 spring boot data 包装 high-level-clientNativeSearchQuery查询有以下问题:
    1. 拼接比较复杂
    2. 不够直观
    3. 依赖es版本
    4. track_total_hits 只能是true或者false,不能指定一个具体的数,笔者的场景 如果为true查询数据量大,如果为false翻页时不能查询总页数。(需求设计时不是下划或者上划刷新)
  2. 使用 spring boot data 包装 high-level-clientsearchTemplate
    1. 虽然mustache语法对初接触者有点难,但相对简洁
    2. 能够做到一些参数的详细控制如 track_total_hits

收获

  1. elasticsearch 模板查询

  2. mstache语法

    1. 怎样传数组, 将参数转换为 JSON,使用 {{#toJson}}parameter{{/toJson}} 会将参数转换为 JSON。参考
    GET _search/template
    {
      "source": "{ "query": { "terms": {{#toJson}}statuses{{/toJson}} }}",
      "params": {
        "statuses" : {
            "status": [ "pending", "published" ]
        }
      }
    }
    

    渲染出来的 DSL 就是:

    {
      "query": {
        "terms": {
          "status": [
            "pending",
            "published"
          ]
        }
      }
    }
    
    1. 传默认值 参考

实践

1. 模拟数据

InfoDocument

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.Document;

import java.util.Date;

@Data
@TypeAlias("infodev")
@Document(indexName = "infodev")
public class InfoDocument {
    @Id
    private long id;
    private String stockCode;
    private Date createDate;
    private String industry;
    private String title;
    private String content;
}

Test

@Test
public void test_info() throws Exception {
    for (int i = 0; i < 100; i++) {
        InfoDocument infoDocument = new InfoDocument();
        infoDocument.setId(i);
        infoDocument.setStockCode("00000" + i);
        infoDocument.setContent("content" + i);
        infoDocument.setTitle("title" + i);
        infoDocument.setCreateDate(new Date());
        infoDocument.setIndustry("industry" + i);
        elasticsearchOperations.save(infoDocument);
    }
}

2. 使用Kibana提交查询模板

PUT _scripts/my-search-template3
{
  "script": {
    "lang": "mustache",
    "source": """
{
"from": "{{from}}{{^from}}0{{/from}}",
"size": "{{size}}{{^size}}10{{/size}}",
"query": {
"bool": {
"must": [
{{#stockCode}}
    {
    "match": {
    "stockCode": "{{stockCode}}"
    }
    }
{{/stockCode}}
{{#industry}}
    ,
    {
    "match": {
    "industry": "{{industry}}"
    }
    }
{{/industry}}
{{#keywords}}
    ,{
    "terms":{
    "title":
      {{#toJson}}keyword{{/toJson}}
    }
    },
    {
    "terms":{
    "content":
      {{#toJson}}keyword{{/toJson}}
    }
    }
{{/keywords}}
]
}
}
}
"""
  }
}

3. 查看传入参数时查询模板的输出

POST _render/template
{
  "id": "my-search-template3",
  "params": {
     "stockCode":"000002",
    "keywords":{
      "keyword":["title1","title2","content2","content3"]
    }
  }
}

输出

{
  "template_output" : {
    "from" : "0",
    "size" : "10",
    "query" : {
      "bool" : {
        "must" : [
          {
            "match" : {
              "stockCode" : "000002"
            }
          },
          {
            "terms" : {
              "title" : [
                "title1",
                "title2",
                "content2",
                "content3"
              ]
            }
          },
          {
            "terms" : {
              "content" : [
                "title1",
                "title2",
                "content2",
                "content3"
              ]
            }
          }
        ]
      }
    }
  }
}

使用查询模板查询

POST infodev/_search/template
{
  "id": "my-search-template3",
  "params": {
    "stockCode":"000002",
    "keywords":{
      "keyword":["title1","title2","content2","content3"]
    }
  }
}

4. Java程序请求

@Test
public void testSearchTemplate() {
    SearchTemplateRequest request = new SearchTemplateRequest();
    request.setRequest(new SearchRequest("infodev"));
    request.setScriptType(ScriptType.STORED);
    request.setScript("my-search-template3");
    Map<String, Object> map = new HashMap<>();
    map.put("stockCode", "000002");
    Map<String, Object> keyword = new HashMap<>();
    List list = new ArrayList<>();
    list.add("title1");
    list.add("title2");
    list.add("content2");
    list.add("content3");
    keyword.put("keyword", list);
    map.put("keywords", keyword);
    request.setScriptParams(map);


    SearchTemplateResponse response = null;
    try {
        response = restHighLevelClient.searchTemplate(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        e.printStackTrace();
    }
    SearchResponse searchResponse = response.getResponse();
}

response的值:

1.png