Es底层查询原理、数据结构、及性能分析

158 篇文章 51 订阅
订阅专栏

  Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询和分析能力,包括全文索引、模糊查询、多条件组合查询、地理位置查询等等,而且具有一定的分析聚合能力。因为其查询场景非常丰富,所以如果泛泛的分析其查询性能是一个非常复杂的事情,而且除了场景之外,还有很多影响因素,包括机型、参数配置、集群规模等等。本文主要是针对几种主要的查询场景,从查询原理的角度分析这个场景下的查询开销,并给出一个大概的性能数字,供大家参考

  Es是一个分布式外壳,实际上执行数据处理的是lucene。es的底层就是lucene。

Lucene查询原理

本节主要是一些Lucene的背景知识,了解这些知识的同学可以略过。

Lucene的数据结构和查询原理

Elasticsearch的底层是Lucene,可以说Lucene的查询性能就决定了Elasticsearch的查询性能。关于Lucene的查询原理大家可以参考以下这篇文章:

Lucene查询原理

Lucene中最重要的就是它的几种数据结构,这决定了数据是如何被检索的,本文再简单描述一下几种数据结构:

  • FST:保存term字典,可以在FST上实现单Term、Term范围、Term前缀和通配符查询等

  • 倒排链:保存了每个term对应的docId的列表,采用skipList的结构保存,用于快速跳跃

 

  • BKD-Tree:BKD-Tree是一种保存多维空间点的数据结构,用于数值类型(包括空间点)的快速查找

 

  • DocValues:基于docId的列式存储,由于列式存储的特点,可以有效提升排序聚合的性能

组合条件的结果合并

了解了Lucene的数据结构和基本查询原理,我们知道:

  1. 对单个词条进行查询,Lucene会读取该词条的倒排链,倒排链中是一个有序的docId列表。
  2. 对字符串范围/前缀/通配符查询,Lucene会从FST中获取到符合条件的所有Term,然后就可以根据这些Term再查找倒排链,找到符合条件的doc。
  3. 对数字类型进行范围查找,Lucene会通过BKD-Tree找到符合条件的docId集合,但这个集合中的docId并非有序的。

现在的问题是,如果给一个组合查询条件,Lucene怎么对各个单条件的结果进行组合,得到最终结果。简化的问题就是如何求两个集合的交集和并集。

1. 对N个倒排链求交集

上面Lucene原理分析的文章中讲过,N个倒排链求交集,可以采用skipList,有效的跳过无效的doc。

2. 对N个倒排链求并集

处理方式一:仍然保留多个有序列表,多个有序列表的队首构成一个优先队列(最小堆),这样后续可以对整个并集进行iterator(堆顶的队首出堆,队列里下一个docID入堆),也可以通过skipList的方式向后跳跃(各个子列表分别通过skipList跳)。这种方式适合倒排链数量比较少(N比较小)的场景。

处理方式二:倒排链如果比较多(N比较大),采用方式一就不够划算,这时候可以直接把结果合并成一个有序的docID数组。

处理方式三:方式二中,直接保存原始的docID,如果docID非常多,很消耗内存,所以当doc数量超过一定值时(32位docID在BitSet中只需要一个bit,BitSet的大小取决于segments里的doc总数,所以可以根据doc总数和当前doc数估算是否BitSet更加划算),会采用构造BitSet的方式,非常节约内存,而且BitSet可以非常高效的取交/并集。

3. BKD-Tree的结果怎么跟其他结果合并

通过BKD-Tree查找到的docID是无序的,所以要么先转成有序的docID数组,或者构造BitSet,然后再与其他结果合并。

查询顺序优化

如果采用多个条件进行查询,那么先查询代价比较小的,再从小结果集上进行迭代,会更优一些。Lucene中做了很多这方面的优化,在查询前会先估算每个查询的代价,再决定查询顺序。

结果排序

默认情况下,Lucene会按照Score排序,即算分后的分数值,如果指定了其他的Sort字段,就会按照指定的字段排序。那么,排序会非常影响性能吗?首先,排序并不会对所有命中的doc进行排序,而是构造一个堆,保证前(Offset+Size)个数的doc是有序的,所以排序的性能取决于(Size+Offset)和命中的文档数,另外就是读取docValues的开销。因为(Size+Offset)并不会太大,而且docValues的读取性能很高,所以排序并不会非常的影响性能。

各场景查询性能分析

上一节讲了一些查询相关的理论知识,那么本节就是理论结合实践,通过具体的一些测试数字来分析一下各个场景的性能。测试采用单机单Shard、64核机器、SSD磁盘,主要分析各个场景的计算开销,不考虑操作系统Cache的影响,测试结果仅供参考。

单Term查询

ES中建立一个Index,一个shard,无replica。有1000万行数据,每行只有几个标签和一个唯一ID,现在将这些数据写入这个Index中。其中Tag1这个标签只有a和b两个值,现在要从1000万行中找到一条Tag1=a的数据(约500万)。给出以下查询,那么它耗时如何呢:
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "Tag1": "a"
        }
      }
    }
  },
  "size": 1
}'
响应:
{"took":233,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":5184867,"max_score":1.0,"hits":...}
这个请求耗费了233ms,并且返回了符合条件的数据总数:5184867条。

对于Tag1="a"这个查询条件,我们知道是查询Tag1="a"的倒排链,这个倒排链的长度是5184867,是非常长的,主要时间就花在扫描这个倒排链上。其实对这个例子来说,扫描倒排链带来的收益就是拿到了符合条件的记录总数,因为条件中设置了constant_score,所以不需要算分,随便返回一条符合条件的记录即可。对于要算分的场景,Lucene会根据词条在doc中出现的频率来计算分值,并取分值排序返回。

目前我们得到一个结论,233ms时间至少可以扫描500万的倒排链,另外考虑到单个请求是单线程执行的,可以粗略估算,一个CPU核在一秒内扫描倒排链内doc的速度是千万级的。

我们再换一个小一点的倒排链,长度为1万,总共耗时3ms。

{"took":3,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":10478,"max_score":1.0,"hits":...}

Term组合查询

首先考虑两个Term查询求交集:

 
  1. 这个请求耗时21ms,主要是做两个倒排链的求交操作,因此我们主要分析skipList的性能。

这个例子中,倒排链长度是1万、500万,合并后仍有5000多个doc符合条件。对于1万的倒排链,基本上不进行skip,因为一半的doc都是符合条件的,对于500万的倒排链,平均每次skip1000个doc。因为倒排链在存储时最小的单位是BLOCK,一个BLOCK一般是128个docID,BLOCK内不会进行skip操作。所以即使能够skip到某个BLOCK,BLOCK内的docID还是要顺序扫描的。所以这个例子中,实际扫描的docID数粗略估计也有几十万,所以总时间花费了20多ms也符合预期。

对于Term查询求并集呢,将上面的bool查询的must改成should,查询结果为:

{"took":393,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":5190079,"max_score":1.0,"hits":...}

花费时间393ms,所以求并集的时间是多于其中单个条件查询的时间。

字符串范围查询

RecordID是一个UUID,1000万条数据,每个doc都有一个唯一的uuid,从中查找0~7开头的uuid,大概结果有500多万个,性能如何呢?
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "RecordID": {
            "gte": "0",
            "lte": "8"
          }
        }
      }
    }
  },
  "size": 1
}
响应:
{"took":3001,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":5185663,"max_score":1.0,"hits":...}
 
查询a开头的uuid,结果大概有60多万,性能如何呢?
 
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "RecordID": {
            "gte": "a",
            "lte": "b"
          }
        }
      }
    }
  },
  "size": 1
}
响应:
{"took":379,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":648556,"max_score":1.0,"hits":...}
倒排链要差许多,同样扫描500万的数据,倒排链扫描只需要不到300ms,而FST上的扫描花费了3秒,基本上是慢十倍的。对于UUID长度的字符串来说,FST范围扫描的性能大概是每秒百万级。

字符串范围查询加Term查询

字符串范围查询(符合条件500万),加上两个Term查询(符合条件5000),最终符合条件数目2600,性能如何?
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "must": [
            {
              "range": {
                "RecordID": {
                  "gte": "0",
                  "lte": "8"
                }
              }
            },
            {
              "term": {
                "Tag1": "a"
              }
            },
            {
              "term": {
                "Tag2": "0"
              }
            }
          ]
        }
      }
    }
  },
  "size": 1
}
结果:
{"took":2849,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":2638,"max_score":1.0,"hits":...}

这个例子中,查询消耗时间的大头还是在扫描FST的部分,通过FST扫描出符合条件的Term,然后读取每个Term对应的docID列表,构造一个BitSet,再与两个TermQuery的倒排链求交集。

数字Range查询

对于数字类型,我们同样从1000万数据中查找500万呢?
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "Number": {
            "gte": 100000000,
            "lte": 150000000
          }
        }
      }
    }
  },
  "size": 1
}
响应:
{"took":567,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":5183183,"max_score":1.0,"hits":...}

这个场景我们主要测试BKD-Tree的性能,可以看到BKD-Tree查询的性能还是不错的,查找500万个doc花费了500多ms,只比扫描倒排链差一倍,相比FST的性能有了很大的提升。地理位置相关的查询也是通过BKD-Tree实现的,性能很高。 

数字Range查询加Term查询

这里我们构造一个复杂的查询场景,数字Range范围数据500万,再加两个Term条件,最终符合条件数据2600多条,性能如何?
请求:
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "must": [
            {
              "range": {
                "Number": {
                  "gte": 100000000,
                  "lte": 150000000
                }
              }
            },
            {
              "term": {
                "Tag1": "a"
              }
            },
            {
              "term": {
                "Tag2": "0"
              }
            }
          ]
        }
      }
    }
  },
  "size": 1
}
响应:
{"took":27,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":2638,"max_score":1.0,"hits":...}

 

这个结果出乎我们的意料,竟然只需要27ms!因为在上一个例子中,数字Range查询耗时500多ms,而我们增加两个Term条件后,时间竟然变为27ms,这是为何呢?

实际上,Lucene在这里做了一个优化,底层有一个查询叫做IndexOrDocValuesQuery,会自动判断是查询Index(BKD-Tree)还是DocValues。在这个例子中,查询顺序是先对两个TermQuery求交集,得到5000多个docID,然后读取这个5000多个docID对应的docValues,从中筛选符合数字Range条件的数据。因为只需要读5000多个doc的docValues,所以花费时间很少。

简单结论

  1. 总体上讲,扫描的doc数量越多,性能肯定越差。
  2. 单个倒排链扫描的性能在每秒千万级,这个性能非常高,如果对数字类型要进行Term查询,也推荐建成字符串类型。
  3. 通过skipList进行倒排链合并时,性能取决于最短链的扫描次数和每次skip的开销,skip的开销比如BLOCK内的顺序扫描等。
  4. FST相关的字符串查询要比倒排链查询慢很多(通配符查询更是性能杀手,本文未做分析)。
  5. 基于BKD-Tree的数字范围查询性能很好,但是由于BKD-Tree内的docID不是有序的,不能采用类似skipList的向后跳的方式,如果跟其他查询做交集,必须先构造BitSet,这一步可能非常耗时。Lucene中通过IndexOrDocValuesQuery对一些场景做了优化。

白话ES写入、查询数据的原理
悟已往之不谏,知来者之可追
03-27 320
前言 ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层Lucene 介绍一下呗?倒排索引了解吗? 问这个,其实面试官就是要看看你了解不了解 es 的一些基本原理,因为用 es 无非就是写入数据,搜索数据。你要是不明白你发起一个写入和搜索请求的时候,es 在干什么,那你真的是… 对 es 基本就是个黑盒,你还能干啥?你唯一能干的就是用 es 的 api 读写数据了。要是出点什么问题,你啥都不知道,那还能指望你什么呢? es 写数据过程 客户端选择一个 node 发送请求过去,这个
es查询大于某个值的数据_Elasticsearch和MySQL查询原理分析与对比
weixin_39881958的博客
11-22 869
导语ES 现在已经越来越火,很多公司会把 MySQL 里面的数据导入到 ES,用 ES 来做海量数据的实时查询。那为什么 MySQL 做不了海量数据的实时查询呢?为什么 ES 可以?本文将从原理上来回答这个问题。基本分析经过分析和对比,得出结论如下:1、ES 天生分布式架构,天然支持海量数据的分片和查询,而 MySQL 不行;2、MySQL 和 ES 底层索引结构导致即便是单片数据查询,...
ES核心干货学习(原理数据结构
li644872790的博客
04-07 3413
ES核心原理数据结构(倒排索引)讲解、便于对ES有个更深入全面的了解,方便后续学习
Elasticsearch进阶篇(二):Elasticsearch查询原理
最新发布
2401_86454378的博客
09-11 1038
例如:当 ES客户端 将 单文档id Get请求发送到节点 2 时,节点 2 将作为协调节点来处理查询请求。
基于Lucene查询原理分析Elasticsearch性能
xuciyisheng的博客
10-30 816
前言 Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询分析能力,包括全文索引、模糊查询、多条件组合查询、地理位置查询等等,而且具有一定的分析聚合能力。因为其查询场景非常丰富,所以如果泛泛的分析查询性能是一个非常复杂的事情,而且除了场景之外,还有很多影响因素,包括机型、参数配置、集群规模等等。本文主要是针对几种主要的查询场景,从查询原理的角度分析这个场景下的查...
es查询原理
TreeCode的博客
07-21 1328
es查询原理: 步骤: 查询请求将被随机发送到一个es节点,该节点成为coordinating node,即协调节点 协调节点根据路由算法算出被查询doc所在的primary shard在哪个节点 协调节点使用轮询调度算法(Round-Robin Scheduling)将请求平均的分配到primary shard和replica shard上,目的是负载均衡 处理请求的节点将请求结果返回给协调节点 协调节点将结果返回给用户 本文参考 千锋教育 搜索引擎 ElasticSearch 视频教程全集(60P)
【数据库学习】ElasticsearchES原理
午后阳光
10-01 6128
Elasticsearch索引的精髓:一切设计都是为了提高搜索的性能 1,正向索引和反向索引 1)正向索引(正排索引) 从文档中查找字符串。关系型数据库使用的是正向索引。 2)反向索引(倒排索引) 从字符串查找文档。搜索引擎lucene使用的是反向索引。 假设有这么几条数据: ID Name Age Sex 1 Kate 24 Female 2 John 24 Male ...
Elasticsearch 常规概念及底层原理
言七墨
11-01 605
一、ES 分布式架构原理 ES设计的理念是分布式搜索引擎底层实现基于Lucene,核心思想是在多台机器上启动多个ES进程实例,组成一个ES集群。 概念描述 接近实时:ES是一个接近实时的搜索平台,这就意味着,从存入一个文档直到文档能够被搜索到有一个轻微的延迟 集群(cluster):一个集群由多个节点(服务器)组成,所有节点一起保存全部数据,每一个集群有一个唯一的名称标识 节点(node):一个节点是一个单一的服务器,是集群的一部分,它存储数据并且参与集群的搜索功能,一个节点可以通过.
ES底层读写工作原理,看这一篇就够了
weixin_64314555的博客
11-24 1328
前言 es 就像是个黑盒,如果你不了解其中的内部原理,你还能干啥?你唯一能干的就是用 es 的 api去做最基本的读写数据了。要是出点什么问题,你啥都不知道,那还能指望你做什么呢? 所以为了能更深入的去了解es内部构造及解决使用过程中出现的问题,知道es底层的工作原理就显得尤为重要了,那么接下来我将展开说说其底层的工作原理是怎样的。 es 写数据过程 客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node (协调节点)。 coordinating nod
Elasticsearch系列---聚合查询原理
黄鹰的专栏
04-17 1147
概要 本篇主要介绍聚合查询的内部原理,正排索引是如何建立的和优化的,fielddata的使用,最后简单介绍了聚合分析时如何选用深度优先和广度优先。 正排索引 聚合查询的内部原理是什么,Elastichsearch是用什么样的数据结构去执行聚合的?用倒排索引吗? 工作原理 我们了解到倒排索引对搜索是非常高效的,但是在排序或聚合操作方面,倒排索引就显得力不从心,例如我们举个实际案例,假设我们有两个文档...
es桶聚合的底层原理数据结构以及算法
05-18
Elasticsearch的聚合是通过使用分布式计算来实现的,底层使用了大量的数据结构和算法。其中最基本的是倒排索引(Inverted Index),它是Elasticsearch的核心数据结构,用于快速检索文本。 在ES的聚合中,常用的是桶...
ES 底层原理
much efforts, much luck
04-03 4940
一、分布式节点 1、client 客户端节点(协调节点) 当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。大多数情况下不需要专用的协调节点,协调节点的功能可以由主节点或数据节点来完成,中小型集群中,专门的协调节点的并没有专用的数据节点必要。 主要功能:负责任务分发和结果汇聚
ES数据结构了解下
渣渣飞的博客
06-21 3763
ES数据结构一:线性数组结构。 class Pojo { constructor(){ this.elements = new Array(0); } //获取数组的长度 size(){ return this.elements.length; } //向数组末尾添加一个元素 add(element){ ...
ES---底层原理
shall潇の菜园
03-17 517
ES底层原理 ES一般情况下分为:主节点,子节点,云端节点 主节点:(master:例如下面的boss)负责创建索引、删除索引、分配分片、追踪集群中的节点状态等 子节点 :负责存储数据,修改索引,查询信息等 云端节点: 负责当数据丢失情况,进行恢复 索引分片 每个索引默认有5个分片,1个副本数 number_of_shards:分片数 number_of_replicas:备份数 【注意:该图是ES的head插件创建索引时的截图】 至于怎么将文件存储到不同的节点,es会根据hashcode(rout
ElasticSearch系列十:ES底层原理探秘
zhou870498的博客
05-30 6999
一、ES基于_version进行乐观锁并发控制 post /index/type/id/_update?retry_on_conflict=5&version=6 ①内部_version版本号:  第一次创建document的_version版本号为1,以后每次对这个document修改或删除操作,_version自动加1。  同时带上数据的版本号,确保es中数据的版本号,跟客户端中的...
【154期】面试官:你能说说 Elasticsearch 查询数据的工作原理是什么吗?
良月柒
03-12 437
程序员的成长之路互联网/程序员/技术/资料共享关注阅读本文大概需要 7分钟。来自:https://doocs.gitee.io/#/面试题ES 写入数据的工作原理是什么啊?ES 查询数...
Elasticsearch查询原理浅析
hellozhxy的博客
08-01 518
Elasticsearch作为一个开源的高扩展的分布式全文搜索引擎。最为人称道就是它对于海量数据近乎实时的强大搜索能力了。这里我们从索引的角度来分析一下,为什么Elasticsearch能够实现快速的检索。通过多级索引的方式减小最前端索引占用的空间,感觉与操作系统防止页表太大,而分为多级页表的思想类似将索引放入内存,尽可能减少磁盘随机读,提高索引查找效率。
ES系列】ES数据结构与DSL语法
m0_50697831的博客
02-06 3390
elasticsearch 数据结构 检索 搜索语法
706
原创
4345
点赞
5822
收藏
3771
粉丝
关注
私信
写文章

热门文章

  • ElasticSearch Query_string + match_phrase 在千亿级检索中的思考 918179
  • ES性能优化最佳实践- 检索性能提升30倍! 911407
  • ES 8.x 向量检索性能测试 & 把向量检索性能提升100倍! 824749
  • 使用openCV比对任意两张图片的相似度(亲测较准确) 472186
  • elasticsearch 7.X全部版本的新特性与重大变化 469887

分类专栏

  • 搜广推 10篇
  • Elasticsearch 158篇
  • ES搜索优化 47篇
  • RAG 53篇
  • 藏经阁 4篇
  • 大模型 13篇
  • 语义检索 5篇
  • elasticsearch源码 11篇
  • NLP 6篇
  • 计算机视觉 2篇
  • Lucene 1篇
  • Lucene源码 1篇
  • 使用chatGPT交互式学习 2篇
  • 优秀的设计思想 4篇
  • 大数据-分布式文件存储系统
  • 高可用 2篇
  • 一年一千题- 力扣 4篇
  • 分布式事务 3篇
  • spring cloud alibaba 4篇
  • MQ 7篇
  • 打卡计划 2篇
  • Netty 13篇
  • k8s 14篇
  • 多线程实战 5篇
  • spirng源码 2篇
  • Spring家族 3篇
  • sentinel 1篇
  • 网关 1篇
  • logstash 3篇
  • MongoDB 3篇
  • 网络 5篇
  • Angus· java start 7篇
  • 在人间凑数的日子 49篇
  • 代码的艺术 20篇
  • 资源分享(书 或 视频 ...) 37篇
  • SSH框架 13篇
  • SSM框架 41篇
  • SpringBoot 34篇
  • Maven学习笔记 15篇
  • 数据结构与算法 11篇
  • java 38篇
  • jvm虚拟机 9篇
  • 数据库 29篇
  • 开发工具 和 教程 25篇
  • ERP项目笔记 10篇
  • Linux 28篇
  • 大数据 2篇
  • 转载学习 4篇
  • 前端 3篇
  • 电商项目 3篇
  • 工具使用教程 7篇
  • 数据库优化 10篇
  • 微服务 20篇
  • Docker 17篇
  • 架构 17篇
  • 面试之路 34篇
  • Redis 11篇
  • NoSql 2篇
  • 代码的最佳实现 4篇
  • 脑图收集分享 10篇
  • 开发经验 109篇
  • tomcat 2篇
  • springboot之bug之路 3篇
  • 软件工程
  • springData 2篇

最新评论

  • Query Rewrite —— 原始query蒸馏,提升召回率,和召回质量

    ErwinOVO: 有相关的参考文献吗

  • 最新开源的解析效果非常好的PDF解析工具MinerU (pdf2md pdf2json)

    水的精神: gpu肯定快呀

  • RAG 基准测试(法律领域)测试数据集分享

    xiaojun2333: 怎么用啊,有没有应用说明

  • 最新开源的解析效果非常好的PDF解析工具MinerU (pdf2md pdf2json)

    源小一: 不过看别人测评,好像A100上跑的贼快

  • 最新开源的解析效果非常好的PDF解析工具MinerU (pdf2md pdf2json)

    源小一: MinerU最近更新了表格识别,但是用纯CPU跑,一个表格要5~10分钟才能跑出来,实在太慢了,GPU还没测试表情包

最新文章

  • 召回的在线评估与离线评估
  • 量化在密集向量检索中的权衡:深入分析索引时间、查询效率与召回效果
  • 稠密向量检索、稀疏向量检索、BM25检索三者对比
2024
09月 4篇
08月 2篇
07月 12篇
05月 11篇
04月 5篇
03月 15篇
02月 20篇
01月 8篇
2023年64篇
2022年68篇
2021年101篇
2020年162篇
2019年312篇
2018年67篇

目录

目录

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

深圳坪山网站建设公司临沂优化网站多少钱茂名网站seo优化南京市网站seo整站优化安阳关键词网站优化代办网站优化用户体验阿里巴巴网站排名优化软件连云港企业网站排名优化多少钱广东网站se0优化公司奉贤区公司网站优化排名网站链接还有什么优化企业网站建立优化网站关键词优化惭云速捷加选福州百度网站优化桐城网站整站优化奉化网站优化网站优化厂通州企业网站优化仙桃本地网站优化公司龙城独立外贸网站优化网站页面有什么优化建议初创创业公司网站优化及维护西双版纳网站优化价格出名的餐饮行业网站优化欢迎咨询枣庄济南网站建设优化宁安优化网站网站搜索优化才能云速捷省力武汉低成本网站优化公司排名阿克苏网站怎么优化网站维护优化具体要做什么辽宁正规的机械行业网站优化香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

深圳坪山网站建设公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化