elasticsearch学习笔记

2020-11-19

被业务赶着走, 没有深入浅出地学习, 只是简单记录业务上遇到的一些问题

分页

es 中有三种分页模式, 分别是 from+size, scrollsize-from

from + size

其实就是偏移(from) n 条记录, 取(size) m 条记录

假设有 5 个分片, 一个 from=100&size=10 的查询, 实际是从 5 个分片分片查出 110 条总共 550 记录, 然后对这 550 记录进行排序, 返回处于 100-110 位置的 10 条记录, 然后丢弃掉 540 条记录

scroll

类似数据库的游标, 但是不建议用于实时数据的查询, 因为 scroll 查询会生成 scroll_id 并缓存, 还会生成历史快照且对于数据的变更不会反映到快照上, 需要耗费一定资源的, 而且也不适用于有跳页的场景

search_after

类似 scroll, 但是可用于实时数据的查询, 如果索引数据有增删改查的变更, 这些变更也会实时的反映到游标上, 但同样的不适用有跳页的场景

query vs filter

简单来说, query 是针对全部记录进行匹配, 除了查询文档是否匹配之外, 还会计算一个_score, _score 表示文档相对于其他文档的匹配程度

filter 只会判断结果是否是否符合查询条件, 性能比 query 更快, 如果一个查询包含queryfilter, es 会先执行 filter 筛选出符合条件记录, 然后再执行 query 进行匹配

排序优化

但我们使用业务字段进行排序时, 排序字段有相同值的记录, 查询的排序结果可能并不一致

例如根据 age 排序, A B C 三条记录 age 都是 18, 第一次查询可能结果为 A B C, 第二次查询可能结果为 B A C

故如果需要唯一排序顺序, 建议增加 ES 记录唯一 id 排序条件, 或根据业务情况增加业务字段排序

例如业务需求根据 age 排序, 查询时可以用 [age, id] 的组合排序条件

nested 结构

举例有如下结构数据

[
  {
    "name": "a",
    "id": 1,
    "comments": [
      {
        "content": "haha",
        "type": 1
      },
      {
        "content": "hehe",
        "type": 2
      }
    ]
  },
  {
    "name": "b",
    "id": 2,
    "comments": [
      {
        "content": "hehe",
        "type": 1
      }
    ]
  }
]

当我们要查询出来 comments 中包含一条 content为hehe, 且type为1 的用户

如果用以下的查询方式, 会发现 name为a 这个不满足条件的数据也会被查询出来

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "comments.content": "hehe" // a.comments[1].content 满足 content为hehe 的查询条件
          }
        },
        {
          "term": {
            "comments.type": 1 // a.comments[2].content 满足 type为1 的查询条件
          }
        }
      ]
    }
  }
}

如果我们希望查出来的数据应该只有 b, 这个时候就需要使用 nested 结构, 再来修改我们的查询语句如下, a 则不会被查询出来

{
  "query": {
    "bool": {
      "nested": {
        "path": "comments",
        "query": {
          "bool": {
            "must": [
              {
                "term": {
                  "comments.content": "hehe"
                }
              },
              {
                "term": {
                  "comments.type": 1
                }
              }
            ]
          }
        }
      }
    }
  }
}