管理es搜索模板

Elasticsearch搜索模板与关系型数据库的存储过程类似。实际就是带变量的查询(使用Mustache模板语言),实际查询时使用模板参数替换变量。
下面示例定义搜索模板:

  1. POST _scripts/<templateid>
  2. {
  3. "script": {
  4. "lang": "mustache",
  5. "source": {
  6. "query": {
  7. "match": {
  8. "title": "{{query_string}}"
  9. }
  10. }
  11. }
  12. }
  13. }

为搜索模板ID,{{query_string}}是参数。
查看已定义的搜索模板:

  1. GET _scripts/<templateid>

执行响应如下:

  1. {
  2. "script" : {
  3. "lang" : "mustache",
  4. "source" : "{\"query\":{\"match\":{\"title\":\"{{query_string}}\"}}}",
  5. "options": {
  6. "content_type" : "application/json; charset=UTF-8"
  7. }
  8. },
  9. "_id": "<templateid>",
  10. "found": true
  11. }

删除搜索模板:

  1. DELETE _scripts/<templateid>

调试es搜索模板

使用搜索模板

可以在某索引下使用搜索模板,需要指定参数。为之前定义搜索模板ID.

  1. GET _search/template
  2. {
  3. "id": "<templateid>",
  4. "params": {
  5. "query_string": "search for these words"
  6. }
  7. }

验证搜索模板

  1. GET _render/template
  2. {
  3. "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}",
  4. "params": {
  5. "statuses" : {
  6. "status": [ "pending", "published" ]
  7. }
  8. }
  9. }

通过_render服务渲染模板,输出结果如下:

  1. {
  2. "template_output": {
  3. "query": {
  4. "terms": {
  5. "status": [
  6. "pending", "published"
  7. ]
  8. }
  9. }
  10. }
  11. }

存储搜索模板也可以使用下面命令进行验证:

GET _render/template/<template_name>
{
  "params": {
    "..."
  }
}

当然也可以在请求体内指定id参数。

生成json字符串

使用{{#toJson}}parameter{{/toJson}}指令可以把参数转成json形式,用于复杂查询:

GET _render/template
{
  "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}",
  "params": {
    "statuses" : {
        "status": [ "pending", "published" ]
    }
  }
}

实际结果应该为:

{
  "query": {
    "terms": {
      "status": [
        "pending","published"
      ]
    }
  }
}

下面是更复杂的示例:

GET _render/template
{
    "source": "{\"query\":{\"bool\":{\"must\": {{#toJson}}clauses{{/toJson}} }}}",
    "params": {
        "clauses": [
            { "term": { "user" : "foo" } },
            { "term": { "user" : "bar" } }
        ]
   }
}

渲染结果为:

{
    "query" : {
      "bool" : {
        "must" : [
          {
            "term" : {
                "user" : "foo"
            }
          },
          {
            "term" : {
                "user" : "bar"
            }
          }
        ]
      }
    }
}

连接数组值

使用{{#join}}array{{/join}}指令可以连接数组的元素并使用逗号进行分隔:

GET _render/template
{
  "source": {
    "query": {
      "match": {
        "emails": "{{#join}}emails{{/join}}"
      }
    }
  },
  "params": {
    "emails": [ "username@email.com", "lastname@email.com" ]
  }
}

渲染结果为:

{
    "query" : {
        "match" : {
            "emails" : "username@email.com,lastname@email.com"
        }
    }
}

也可以指定分隔符:

GET _render/template
{
  "source": {
    "query": {
      "range": {
        "born": {
            "gte"   : "{{date.min}}",
            "lte"   : "{{date.max}}",
            "format": "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}"
        }
      }
    }
  },
  "params": {
    "date": {
        "min": "2016",
        "max": "31/12/2017",
        "formats": ["dd/MM/yyyy", "yyyy"]
    }
  }
}

渲染结果为:

{
    "query" : {
      "range" : {
        "born" : {
          "gte" : "2016",
          "lte" : "31/12/2017",
          "format" : "dd/MM/yyyy||yyyy"
        }
      }
    }
}

指定缺省值

可以使用{{var}}{{^var}}default{{/var}}指令指定缺失值:

{
  "source": {
    "query": {
      "range": {
        "line_no": {
          "gte": "{{start}}",
          "lte": "{{end}}{{^end}}20{{/end}}"
        }
      }
    }
  },
  "params": { ... }
}

当params参数值为{ “start”: 10, “end”: 15 }时解析结果为:

{
    "range": {
        "line_no": {
            "gte": "10",
            "lte": "15"
        }
  }
}

当params参数值为{ “start”: 10 }时解析结果为:

{
    "range": {
        "line_no": {
            "gte": "10",
            "lte": "20"
        }
    }
}

条件表达式

条件子句不能使用json形式表达,模板必须作为字符串进行传输。假设我们需要在line字段上执行match查询,其中start和end作为行号进行过滤是可选的。参数如下:

{
    "params": {
        "text":      "words to search for",
        "line_no": { 
            "start": 10,
            "end":   20
        }
    }
}

对应查询模板:

{
  "query": {
    "bool": {
      "must": {
        "match": {
          "line": "{{text}}" 
        }
      },
      "filter": {
        {{#line_no}} 
          "range": {
            "line_no": {
              {{#start}} 
                "gte": "{{start}}" 
                {{#end}},{{/end}} 
              {{/start}}
              {{#end}} 
                "lte": "{{end}}" 
              {{/end}}
            }
          }
        {{/line_no}}
      }
    }
  }
}

{{#line_no}} 表示如果line_no存在,则解析{{/line_no}}之间的内容。块内的模板语法也类似,都是实现了条件判断功能,伪代码表达如下:

if 条件  then
   表达式
end if

实际应用可能会用到if else的功能,在模板中的语法为:{{^line_no}}。

URL编码

{{#url}}value{{/url}}指令能以HTML编码形式对字符串值进行编码,下面示例对url编码:

GET _render/template
{
    "source" : {
        "query" : {
            "term": {
                "http_access_log": "{{#url}}{{host}}/{{page}}{{/url}}"
            }
        }
    },
    "params": {
        "host": "https://www.elastic.co/",
        "page": "learn"
    }
}

响应结果如下:

{
    "template_output" : {
        "query" : {
            "term" : {
                "http_access_log" : "https%3A%2F%2Fwww.elastic.co%2F%2Flearn"
            }
        }
    }
}