在线查询修复的实现

在线查询修复的实现 #

在某些情况下,您可能会碰到业务代码生成的 QueryDSL 存在不合理的情况,一般做法是需要修改业务代码并发布上线, 如果上线新版本需要很长的时间,比如没有到投产窗口,或者封网,又或者需要和其他的代码提交一起上线,往往意味着需要大量的测试, 而生产环境的故障要立马解决,客户不能等啊,怎么办?

别着急,您可以使用极限网关来对查询进行动态修复。

举个例子 #

比如下面的这个查询:

GET _search
{
 "size": 1000000
 , "explain": true
}

参数 size 设置的太大了,刚开始没有发现问题,随着数据越来越多,返回的数据太多势必会造成性能的急剧下降, 另外参数 explain 的开启也会造成不必要的性能开销,一般只在开发调试的时候才会用到这个功能。

通过在网关里面增加一个 request_body_json_set 过滤器,可以动态替换指定请求体 JSON PATH 的值,上面的例子对应的配置如下:

flow:
- name: rewrite_query
  filter:
    - request_body_json_set:
       path:
         - explain -> false
         - size -> 10
   - dump_request_body:
   - elasticsearch:
       elasticsearch: dev

通过重新设置 explainsize 参数,现在我们查询发给 Elasticsearch 前会被改写成如下格式:

{
 "size": 10, "explain": false
}

成功修复线上问题。

再举个例子 #

看下面的这个查询,编写代码的程序员写错了需要查询的字段名,应该是 name,但是写成了 name1,参数 size 也设置的特别大,如下:

GET medcl/_search
{
  "aggs": {
    "total_num": {
      "terms": {
        "field": "name1",
        "size": 1000000
      }
    }
  }
}

然后,系统居然上线了,这不查询就出问题了嘛。 哎,别着急,在网关请求流程里面增加如下过滤器配置就行了:

flow:
- name: rewrite_query
  filter:
    - request_body_json_set:
       path:
         - aggs.total_num.terms.field -> "name"
         - aggs.total_num.terms.size -> 10
         - size -> 0
   - dump_request_body:
   - elasticsearch:
       elasticsearch: dev

上面的配置,我们通过请求体 JSON 的路径直接替换了其数据,并且新增了一个参数来不返回查询文档,因为只需要聚合结果就行了。

再举个例子 #

用户的查询为:

{
  "query":{
	"bool":{
	   "should":[{"term":{"isDel":0}},{"match":{"type":"order"}}]
	}	
}
}

现在希望将其中的 term 查询换成等价的 range 查询,即如下:

{
  "query":{
	"bool":{
	   "should":[{ "range": { "isDel": {"gte": 0,"lte": 0 }}},{"match":{"type":"order"}}]
	}	
}
}

使用下面的配置即可:

flow:
  - name: rewrite_query
    filter:
      - request_body_json_del:
          path:
            - query.bool.should.[0]
      - request_body_json_set:
          path:
            - query.bool.should.[1].range.isDel.gte -> 0
            - query.bool.should.[1].range.isDel.lte -> 0
      - dump_request_body:
      - elasticsearch:
          elasticsearch: dev

上面的配置,首先使用了一个 request_body_json_del 来删除查询 should 里面的第一个元素,也就是要替换掉的 Term 子查询, 然后现在只剩一个 Match 查询了,现在增加一个 Should 的子查询,新增下标的注意应该为 1,分别设置 Range 查询的各个属性即可。

进一步完善 #

上面的例子都是直接替换查询,不过一般情况下,你可能还需要进行一个判断来决定是否进行替换,比如当 _ctx.request.body_json.query.bool.should.[0].term.isDel JSON 字段存在才进行替换,网关的 条件判断非常灵活如下,配置如下:

flow:
  - name: cache_first
    filter:
      - if:
          and:
            - has_fields: ['_ctx.request.body_json.query.bool.should.[0].term.isDel']
        then:
          - request_body_json_del:
              path:
                - query.bool.should.[0]
          - request_body_json_set:
              path:
                - query.bool.should.[1].range.isDel.gte -> 0
                - query.bool.should.[1].range.isDel.lte -> 0
          - dump_request_body:
      - elasticsearch:
          elasticsearch: dev

完美!