es入门心路历程

背景

作为服务端开发,感觉接触到es是早晚的事情~ 之前在交易团队里负责的模块查询条件比较单一,虽然听说过别的模块使用es,但是自己一直都没有接触过,看官方文档也是迷迷糊糊不知所云。最近刚好有机会因为c端的聚合查询接触到了es,经历了从一无所知到有一点了解的过程,希望这篇文章对同样处境的小伙伴们能有所帮助。

为什么要用ES

1、业务需要根据某一个mysql字段聚合检索,然后根据规则找出top数据,还要实现分页。这种聚合且&排序&分页的操作,不能通过简单的数据库查询完成,但是es却支持的很好。
2、多表联合查询,且表里的数据量比较大。这种情况会导致mysql产生很多慢sql,很大程度上给服务带来了一定的风险。稍有不慎数据库就会被打挂影响到主业务流程,所以就用es把所有查询条件放在一起,进行查询。

ES基础解释

我们使用最多的是关系型数据库,这相当于是把一个表现力丰富的对象塞到一个非常大的电子表格中,为了适应表结构,必须设法将这个对象扁平化—​通常一个字段对应一列—​而且每次查询时又需要将其重新构造为对象。不同的关系类型也要放在不同的表里进行区分。

Elasticsearch 是 面向文档 的,意味着它存储整个对象或 文档。Elasticsearch 不仅存储文档,而且 索引 每个文档的内容,使之可以被检索。在 Elasticsearch 中,我们对文档进行索引、检索、排序和过滤—​而不是对行列数据。这是一种完全不同的思考数据的方式,也是 Elasticsearch 能支持复杂全文检索的原因。Elasticsearch 使用 JavaScript Object Notation(或者 JSON)作为文档的序列化格式。JSON 序列化为大多数编程语言所支持,并且已经成为 NoSQL 领域的标准格式。 它简单、简洁、易于阅读。

下面针对一些常用到的es知识做下简介,其实我比较推荐大家在初步了解之后认真学习一下es的官方文档,文档中对es的入门以及它的一些功能解释的很详细。
下面先贴上es官方文档地址:Elasticsearch: 权威指南

索引

es的一条数据就是一个文档,就相当于mysql中的一行。文档存储数据到 Elasticsearch 的行为叫做 索引 。同样,索引也有自己的名词解释,就是文档的结构,相当于mysql中的字段类型定义。一个 Elasticsearch 集群可以 包含多个 索引 ,相应的每个索引可以包含多个 类型 。 这些不同的类型存储着多个 文档 ,每个文档又有 多个 属性 。下面举例如何新建一个索引:


PUT  java_developer //索引名称
{
  "settings": {
    "number_of_shards": 1,  //主分片
    "number_of_replicas": 1 //每个主分片的副本分片
  },
  "mappings": {
    "properties": {  //属性
        "userId": {
          "type": "long"
        },
        "userName": {
          "type": "keyword"
        }
      }
    }
}
分片 & 副本

es的主分片和副本分片关系就像是mysql的读写库和只读库一样。主分片主要是用来做写操作的,副本分片是为了分担主分片的读压力,并且在主分片发生故障时,可以快速把副本分片变成主分片,不至于数据丢失。

路由

当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?当我们创建文档时,它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢?

首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:

shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

单分片好处 & 压力

单分片可以避免请求到来之后,根据路由计算的转发流程。也避免了根据路由字段的检索时扫描所有分片聚合的流程,因为单节点就拥有所有数据,存储和查询过程都简单。但是单节点同时也会承受很大的压力,所有的请求都会聚集在单个节点上,存在一定的风险隐患。

多分片 & 路由指定

所有的文档 API( get 、 index 、 delete 、 bulk 、 update 以及 mget )都接受一个叫做 routing 的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中

多分片之间的交互

在这里插入图片描述

我们可以发送请求到集群中的任一节点。 每个节点都有能力处理任意请求。 每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上。 在下面的例子中,将所有的请求发送到 Node 1 ,我们将其称为 协调节点(coordinating node) 。

常用知识点整理记录:

查询所有数量:
POST qa_answer_pro/_doc/_search
{
  "track_total_hits":true,
  "query": {
    "match_all": {}
  }
}

聚合:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("status", 0));
      
        //todo  答案数量条件
        SearchSourceBuilder query = new SearchSourceBuilder();
        query.query(boolQuery);

        //聚合标签
        //todo  最大标签数 size
        TermsAggregationBuilder topBuilder = AggregationBuilders.terms("聚合名称").field("聚合字段").size(limit);

        // 获取每个标签下top1有用数
        AggregationBuilder top = AggregationBuilders.topHits("命中名称").size(1).sort("排序字段", SortOrder.DESC);
        topBuilder.subAggregation(top);

        // 分组排序规则
        topBuilder.order(BucketOrder.aggregation("聚合玩后内部排序字段名称", false));
        MaxAggregationBuilder order = AggregationBuilders.max("聚合玩后内部排序字段名称").field("排序字段");
        topBuilder.subAggregation(order);

        // 聚合查询
        query.aggregation(topBuilder);
        SearchResult searchResult = elasticSearchRepo.getSearchResult(query.toString(), Index(), IndexType());
        List<TermsAggregation.Entry> buckets = searchResult.getAggregations().getTermsAggregation("聚合玩后内部排序字段名称").getBuckets();
        for (TermsAggregation.Entry bucket : buckets) {
            AA model = bucket.getTopHitsAggregation("top_question_hits").getSourceAsObject(AA.class, false);
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值