正文

整合Elasticsearch相关知识点

【版权所有,文章不得已任何形式转载,违者必究】

文章目录

  • 正文
  • 1.介绍
    • Elasticsearch
  • 2.对比
      • 2.1.1Solr
      • 2.1.2 Lucene
    • 2.2 Elasticsearch和Solr比较
  • 3.基本概念
    • 3.1核心概念
    • Index索引
    • Type类型(高版本中慢慢被弃用)
    • Document文档
    • Field字段
    • mapping映射
    • 分片和复制 shards&replicas
    • 3.2 ElasticSearch和数据库对别
  • 4.安装
      • 4.1 windows
        • 一、安装jdk
        • 二、安装ElasticSearch
        • 三、安装ElasticSearch-head插件
        • 四、ElasticSearch安装为Windows服务
      • 4.2其他ES必要的插件
        • Elasticsearch插件一——-head插件安装详解
        • [Elasticsearch插件二—— kibana插件安装详解](https://blog.csdn.net/laoyang360/article/details/51472888)
        • [Elasticsearch插件三—— Marvel插件安装详解](https://blog.csdn.net/laoyang360/article/details/51472902)
        • [Elasticsearch插件四—— logstash插件安装详解](https://blog.csdn.net/laoyang360/article/details/51472914)
        • [Elasticsearch插件五—— graph插件安装详解](https://blog.csdn.net/laoyang360/article/details/51472931)
        • [Elasticsearch插件六—— 分词 IK analyzer插件安装详解](https://blog.csdn.net/laoyang360/article/details/51472953)
        • [Elasticsearch5.4.0 IK分词插件安装详解](https://blog.csdn.net/laoyang360/article/details/74090357)
    • 5.ES对外接口
  • 5.1 ESTful API接口
    • a 创建索引
    • b.插入数据
      • 语法二
    • c.更新数据
      • Partial Update 局部更新
    • d. 删除数据
    • e.(批量查询和批量增删改)Bulk Operation
  • 6:Elasticsearch查询(必须掌握)
    • 6.1 ElasticSearch Rest API
    • 搜索(_search)
      • **6.1.1:通用语法**
      • **6.1.2:query string search 条件语法**
      • 6.1.3.query DSL(用json来组装查询条件,可以构建各种复杂的语法)
        • 6.1.3.1 full-text search全文搜索
          • match
          • multi_match 查询词匹配多个属性
          • phrase search 短语搜索
          • (4) 优化短语搜索: rescore
          • (5) match_phrase_prefix(搜索推荐)
        • 6.1.3.2fuzzy search ==模糊搜索==
        • **6.1.3.3term search**
        • 6.1.3.4query filter(过滤数据,)
      • 6.1.4scroll search 滚动数据
    • 聚合(aggs)
      • 6.2 C#操作库
        • 简单的查询和插入
        • 6.3 JAVA 类库
    • 6 Es 的坑
    • 7.其他
      • 7.1elasticsearch写入数据原理?
      • 7.2倒排索引实现原理
    • 8.elasticsearch相关面试题
  • 1、elasticsearch了解多少,说说你们公司es的集群架构,索引数据大小,分片有多少,以及一些调优手段 。
    • 1.1、设计阶段调优
    • 1.2、写入调优
    • 1.3、查询调优
    • 1.4、其他调优
  • 2、elasticsearch的倒排索引是什么?
  • 3、elasticsearch 索引数据多了怎么办,如何调优,部署?
    • 3.1 动态索引层面
    • 3.2 存储层面
    • 3.3 部署层面
  • 4、elasticsearch是如何实现master选举的?
  • 5、详细描述一下Elasticsearch索引文档的过程?
  • 6、详细描述一下Elasticsearch搜索的过程?
  • 7、Elasticsearch在部署时,对Linux的设置有哪些优化方法?
  • 8、lucence内部结构是什么?
    • 鸣谢:
    • 附图

1.介绍

  • Elasticsearch

    ​ Elasticsearch是一个实时分布式搜索和分析引擎。它让你以前所未有的速度处理大数据成为可能。
    它用于全文搜索、结构化搜索、分析以及将这三者混合使用:
    维基百科使用Elasticsearch提供全文搜索并高亮关键字,以及输入实时搜索(search-asyou-type)和搜索纠错(did-you-mean)等搜索建议功能。

    • 英国卫报使用Elasticsearch结合用户日志和社交网络数据提供给他们的编辑以实时的反馈,以便及时了解公众对新发表的文章的回应。
    • StackOverflow结合全文搜索与地理位置查询,以及more-like-this功能来找到相关的问题和答案。
    • Github使用Elasticsearch检索1300亿行的代码。

    Elasticsearch是一个基于Apache Lucene™的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
    但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
    Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API 来隐藏Lucene的复杂性,从而让全文搜索变得简单。

2.对比

2.1.1Solr

Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器。Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化

Solr可以独立运行,运行在Jetty、Tomcat等这些Servlet容器中,Solr 索引的实现方法很简单,用 POST 方法向 Solr 服务器发送一个描述 Field 及其内容的 XML 文档,Solr根据xml文档添加、删除、更新索引 。Solr 搜索只需要发送 HTTP GET 请求,然后对 Solr 返回Xml、json等格式的查询结果进行解析,组织页面布局。Solr不提供构建UI的功能,Solr提供了一个管理界面,通过管理界面可以查询Solr的配置和运行情况。

solr是基于lucene开发企业级搜索服务器,实际上就是封装了lucene。Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的文件,生成索引;也可以通过提出查找请求,并得到返回结果。

2.1.2 Lucene

Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。

全文搜索引擎是名副其实的搜索引擎,国外具代表性的有Google、Fast/AllTheWeb、AltaVista、Inktomi、Teoma、WiseNut等,国内著名的有百度(Baidu)。它们都是通过从互联网上提取的各个网站的信息(以网页文字为主)而建立的数据库中,检索与用户查询条件匹配的相关记录,然后按一定的排列顺序将结果返回给用户,因此他们是真正的搜索引擎。

从搜索结果来源的角度,全文搜索引擎又可细分为两种,一种是拥有自己的检索程序(Indexer),俗称“蜘蛛”(Spider)程序或“机器人”(Robot)程序,并自建网页数据库,搜索结果直接从自身的数据库中调用,如上面提到的7家引擎;另一种则是租用其他引擎的数据库,并按自定的格式排列搜索结果,如Lycos引擎。

2.2 Elasticsearch和Solr比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkORLyGP-1608803935838)(H:\doc\markdown\354604-20180122010705803-1082290454.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHrF4GAx-1608803935840)(H:\doc\markdown\354604-20180122010730865-1548826450.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u73VUTsL-1608803935841)(H:\doc\markdown\354604-20180122010754100-1951694800.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0CQtxnfG-1608803935842)(H:\doc\markdown\354604-20180122011131225-347761833.png)]

ElasticSearch vs Solr 总结

  • es基本是开箱即用,非常简单。Solr安装略微复杂一丢丢

  • Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。

  • Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。

  • Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑

  • Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;

    ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索。

    Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

  • Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。

3.基本概念

3.1核心概念

3.2 ElasticSearch和数据库对别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlI62DM4-1608803935843)(H:\doc\markdown\Elasticsearch-mysql.png)]

4.安装

4.1 windows

Linux下大同小异这边就不做描述了

一、安装jdk

由于ElasticSearch 5.x 往后依赖于JDK 1.8的,所以现在我们下载JDK 1.8或者更高版本。下载JDK1.8,下载完成后安装。

安装ElasticSearch高版本时使用自带JDK

平时使用jdk8,es7启动会报错。
需要修改elasticsearch-env配置文件,使用自带jdk。

传送门:安装ElasticSearch7.6使用自带JDK

二、安装ElasticSearch

1.ElasticSearch下载地址:

https://www.elastic.co/downloads/elasticsearch

2.下载安装包后解压

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-coHSPVIW-1608803935844)(H:\doc\markdown\1676314-20190918111243712-111248218.png)]

3.进入bin目录下,双击执行elasticsearch.bat

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rhIWlA62-1608803935845)(H:\doc\markdown\1676314-20190918111219472-1639773577.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Uklhbgn-1608803935846)(H:\doc\markdown\1676314-20190918111601780-92205386.png)]

4.看到started说明启动成功,打开浏览器测试一下,如下图

http://localhost:9200

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pqBi4lcB-1608803935846)(H:\doc\markdown\1676314-20190918111749049-1111981258.png)]

三、安装ElasticSearch-head插件

1、安装node环境(更详细教程查看博主node安装教程篇)
网址:https://nodejs.org/en/download/ 下载Windows版msi的,下载完直接安装,一直确定

安装完后cmd查看版本node-v

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GmWFDcwA-1608803935847)(H:\doc\markdown\1676314-20190918112157223-1154062173.png)]

2、安装grunt

grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作,5.x里之后的head插件就是通过grunt启动的。因此需要安装grunt.

npm install -g grunt-cli

查看版本号 grunt -version

注意:如果提示grunt命令不存在,转移博主node安装教程篇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMZqBM1b-1608803935848)(H:\doc\markdown\1676314-20190918112807159-242101363.png)]

3.下载head插件

1.网址:https://github.com/mobz/elasticsearch-head下载安装包

2.解压

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADh3v2eN-1608803935848)(H:\doc\markdown\1676314-20190918113227003-1855735893.png)]

3.进入head文件夹下,执行命令:npm install (此处是为安装进行安装pathomjs)

如果安装速度慢,设置成淘宝的镜像重新安装 npm config set registry https://registry.npm.taobao.org

4.安装完成之后npm run start或grunt server,启动head插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q7Ou8yW2-1608803935849)(H:\doc\markdown\1676314-20190918113525635-1487341798.png)]

5.修改es使用的参数.编辑D:\elasticsearch\elasticsearch-7.3.2-windows-x86_64\elasticsearch-7.3.2\config\elasticsearch.yml文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0AOn77f-1608803935849)(H:\doc\markdown\1676314-20190918113857490-589279016.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrvAv7sU-1608803935850)(H:\doc\markdown\1676314-20190918114138501-1661263063.png)]

# 增加新的参数,这样head插件可以访问es
http.cors.enabled: true
http.cors.allow-origin: "*"
@注意,设置参数的时候:后面要有空格!

6.修改完配置将es重启,浏览器访问 http://localhost:9100

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2TUaaRk-1608803935851)(H:\doc\markdown\1676314-20190918114348525-202238458.png)]

到此,Elasticsearch和ElasticSearch-head已经装好了。

四、ElasticSearch安装为Windows服务

1.elasticsearch的bin目录下有一个elasticsearch-service.bat

2.cmd 进入bin目录下执行: elasticsearch-service.bat install

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uUEDB9tP-1608803935851)(H:\doc\markdown\1676314-20190918114616082-384616548.png)]

3.查看电脑服务es已经存在了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ByUNKDmg-1608803935852)(H:\doc\markdown\1676314-20190918114641264-938114959.png)]

elasticsearch-service.bat后面还可以执行这些命令
install: 安装Elasticsearch服务
remove: 删除已安装的Elasticsearch服务(如果启动则停止服务)
start: 启动Elasticsearch服务(如果已安装)
stop: 停止服务(如果启动)
manager:启动GUI来管理已安装的服务

4.2其他ES必要的插件

Elasticsearch插件一——-head插件安装详解
Elasticsearch插件二—— kibana插件安装详解
Elasticsearch插件三—— Marvel插件安装详解
Elasticsearch插件四—— logstash插件安装详解
Elasticsearch插件五—— graph插件安装详解
Elasticsearch插件六—— 分词 IK analyzer插件安装详解
Elasticsearch5.4.0 IK分词插件安装详解

5.ES对外接口

5.1 ESTful API接口

官方API

a 创建索引

需求

创建一个简单的空索引,索引的名字为testindex

语法

请求url http://127.0.0.1:9200/{索引名}
请求体: {
“settings”:{
“index”:{
“number_of_shards”:“2”,
“number_of_replicas”:“0”
}
}
}
Http请求方式 PUT
说明 索引必须小写

Example

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qTamHAeY-1608803935852)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20201223174150827.png)]

请求体说明:

number_of_shards为片数,

number_of_replicas为副本数。点击发送之后,状态码为200表示创建成功,刷新可以看到多了一个testindex索引

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nymmpnp3-1608803935853)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20201224092936216.png)]

b.插入数据

  • 需求

    向索引testindex中插入一条user类型的数据,_id设置为100,数据:

{    "id":100,"name":"jack","age":18,"sex":"男"
}
  • 语法一
请求url http://127.0.0.1:9200/{索引名}/{类型}/{Id}
请求体: 请求数据
Http请求方式 PUT
返回值说明 took:1 耗费了3毫秒

time_out:false 没有超时

_shards.total: 请求打到了x个shard(primary shard或replica shard)上拿数据

_shards.successful:x x个请求成功的shard

_shards.failed:0 0个请求失败的shard

hits.total:2 查询到2个document

hits.hits._score:1 在这次搜索中这个document的相关度匹配分数为1,越相关就越匹配分数就越高

hits.hits._source document数据

  • 语法二

请求url http://127.0.0.1:9200/{索引名}/{类型}
请求体: 请求数据
Http请求方式 POST
备注 会随机生成一个Id(UUID)
说明 记录不存在就是创建, 否则是全量替换.

备注: 官方6.X不支持一个index多个type了[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QhGwFGq6-1608803935853)(H:\doc\markdown\813478-20181129113625393-141937545.png)]

在6.0.0或者更高版本中仅支持单Mapping。对于5.X版本中多个Mapping依旧可以使用。计划在7.0.0中完全移除Mapping【移除是符合情理的,你看现在就只支持单Mapping,跟直接访问index没啥区别了】

https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html

c.更新数据

在elasticsearch中,文档数据是不可以修改的,但是可以通过覆盖的方式进行更新。

Partial Update 局部更新

  • 需求

    向索引testindex中的这条文档数据改为age=20,数据:

{    "id":100,"name":"jack","age":18,"sex":"男"
}
  • 语法
请求url http://127.0.0.1:9200/{索引名}/{类型}/{Id}/_update
请求体: { “doc”: { “属性名” : “value” … } }
Http请求方式 POST
说明 在应用程序中, 全量替换是先从ES中查询出记录, 然后在修改, 一个属性都不能少. 而部分更新就不用先从ES查询记录了, 可以直接修改, 且不用所有属性都列出.

d. 删除数据

需求

删除索引数据testindex 下的 1001即可,相应的数据如下,表示删除成功。

语法

请求url http://127.0.0.1:9200/{index}/{type}/{id}
Http请求方式 DELETE
备注 删除一个文档不会立即从磁盘上移除,只是被标记为已删除状态,Elasticsearch会在你之后添加更多索引的时候在后台进行删除内容的清理。

Example

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dv9AINZ8-1608803935854)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20201224105732088.png)]

e.(批量查询和批量增删改)Bulk Operation

批量查询和批量增删改的语法不同, 所以分开来介绍.

批量查询

GET /_mget
{"docs" : [{"_index" : "company","_type" : "employee","_id" : 1},{"_index" : "company","_type" : "employee","_id" : 2}]
}GET /company/_mget
{"docs" : [{"_type" : "employee","_id" : 1},{"_type" : "employee","_id" : 2}]
}GET /company/employee/_mget
{"ids" : [1,2]
}

批量增删改

(1) 语法

每一个操作要两个json串,语法如下:

POST /index/type/_bulk
{"action": {"metadata"}}
{"data"}
123

index和type可以放入metadata中. 每个json串不能换行, 只能放一行. 同时一个json串和一个json串之间, 必须有一个换行.

(2) action类型

  • delete

    删除.

  • create

    强制创建. PUT /index/type/id/_create

  • index

    创建或替换.

  • update

    属于部分更新.

6:Elasticsearch查询(必须掌握)

6.1 ElasticSearch Rest API

搜索(_search)

6.1.1:通用语法

(1) 搜索所有index数据.

GET /_search
1

(2) 搜索指定index, type下的数据(index和type可以有多个)

GET /index1/_search
GET /index1,index2/_search
GET /index1/type1/_search
GET /index1/type1,type2/_search
GET /index1,index2/type1,type2/_search
12345

(3) 搜索所有index下的指定type的数据.

GET /_all/employee,product/_search

6.1.2:query string search 条件语法

这个查询就类似于HTTP里的GET请求, 参数放在URL上.

6.1.2.1 语法

GET /index/type/_search?q=属性名:属性值
GET /index/type/_search?q=+属性名:属性值
GET /index/type/_search?q=-属性名:属性值
也可以省略属性名, 直接q=属性值
GET /index/type/_search?q=属性值

6.1.2.2 + 和 - 的区别

默认是+, 指必须包含该字段, - 指不包含该字段.

6.1.2.3实例

GET /website/article/_search?q=author_id:11403
GET /website/article/_search?q=-author_id:11403
GET /website/article/_search?q=11403
123

6.1.2.4 _all metadata的原理

GET /index/type/_search?q=属性值.

这个语句是从所有属性中搜索包含指定的关键字的数据. 那么ES在搜索时是遍历所有document中的每一个field吗? 不是的, 我们在插入一条document时, ES会自动将多个field的值, 全部用字符串的方式串联起来, 变成一个长的字符串(以空格作为分隔符),作为_all field的值,同时进行分词建立倒排索引. 如果在搜索时没有指定属性名, 就会默认搜索_all field. (生产环境不使用)

6.1.3.query DSL(用json来组装查询条件,可以构建各种复杂的语法)

DSL, Domain Specified Language,特定领域的语言. 这个查询就类似于HTTP里的POST请求, 参数放在body中.

实例: 从website索引中查询所有文章

GET /website/article/_search
{"query": {"match_all": {}}
}

6.1.3.1 full-text search全文搜索

match

a. 搜索标题中包含first或second的文章

GET /website/article/_search
{"query": {"match": {"title": "first second"}}
}
或者GET /website/article/_search
{"query": {"match": {"title": {"query": "first second", "operator": "or"}}}
}
或者
GET /website/article/_search
{"query": {"bool": {"should": [{"match": {"title":"first"}},{"match": {"title":"second"}}]}}
}

b. 搜索标题中包含first和second的文章

GET /website/article/_search
{"query": {"match": {"title": {"query": "first second", "operator": "and"}}}
}
或者
GET /website/article/_search
{"query": {"bool": {"must": [{"match": {"title": "first"}},{"match": {"title": "second"}}]}}
}

c. 搜索标题中至少包含first, second, third, fourth中三个单词的文章.

GET /website/article/_search
{"query": {"match": {"title": {"query": "first second third fourth","minimum_should_match": "75%"}}}
}
或者
GET /website/article/_search
{"query": {"bool": {"should": [{"match": {"title": "first"}},{"match": {"title": "second"}},{"match": {"title": "third"}},{"match": {"title": "fourth"}}],"minimum_number_should_match": 3}}
}

d. 从website索引中查询, 标题必须包含elasticsearch,内容可以包含elasticsearch也可以不包含,作者id必须不为111.

GET /website/article/_search
{"query": {"bool": {"must": [{"match": {"title":"elasticsearch"}}],"should": [{"match": {"content":"elasticsearch"}}], "must_not": [{"match": {"author_id":"111"}}]}}
}

e. 从website索引中查询, 标题包含first, 同时按作者id降序排序

GET /website/article/_search
{"query": {"match": {"title": "first"}},"sort": [{"author_id": {"order": "desc"}}]
}

f. 从website索引中分页查询,总共3篇文章,假设每页就显示1篇文章,现在显示第2页

GET /website/article/_search
{"query": {"match_all": {}},"from": 1,"size": 1
}

g. 从website索引中查询所有文章, 只显示post_date, title两个属性.

GET /website/article/_search
{"query": {"match_all": {}},"_source": ["post_date","title"]
}

h. 搜索标题中包含 article 的文章, 如果标题中包含first或second就优先搜索出来, 同时, 如果一个文章标题包含first article, 另一个文章标题包含second article, 包含first article的文章要优先搜索出来.

//通过加权重来处理, 默认权重为1
GET /website/article/_search
{"query": {"bool": {"must": [{"match": {"title": "article"}}],"should": [{"match": {"title": {"query": "first","boost" : 3}}},{"match": {"title": {"query": "second","boost": 2}}}]}}
}
multi_match 查询词匹配多个属性

multi_match 用于查询词匹配多个属性. 这里涉及到几种匹配策略:

  • best-fields
    doc的某个属性匹配尽可能多的关键词, 那么这个doc会优先返回.
  • most-fields
    某个关键词匹配doc尽可能多的属性, 那么这个doc会优先返回.
  • cross_fields
    跨越多个field搜索一个关键词.

best-fields和most-fields的区别:
比如, doc1的field1匹配的三个关键词, doc2的field1, field2都匹配上了同一个关键词. 如果是best-fields策略, 则doc1的相关度分数要更高, 如果是most-fields策略, 则doc2的相关度分数要更高.

实例:

a. 使用best_fields策略, 从title和content中搜索"my third article".

GET /website/article/_search
{"query": {"multi_match": {"query": "my third article","type": "best_fields", "fields": ["title","content"]}}
}

b. 从title和content中搜索"my third article", 且这三个单词要连在一起.

GET /website/article/_search
{"query": {"multi_match": {"query": "my third article","type": "cross_fields","operator": "and","fields": ["title","content"]}}
}

(3) dis_max

在我们进行多个条件的全文搜索时, 最后的计算出的相关度分数是根据多个条件的匹配分数综合而来的, 比如score = (score1 + score2) / 2, 如果我们想让最终的相关度分数等于多个条件匹配分数中的最大值, 即score = max(score1, score2), 则可以使用dis_max.

实例: 搜索title或content中包含first或article的文章

GET /website/article/_search
{"query": {"bool": {"should": [{"match": {"title": "first article"}},{"match": {"content": "first article"}}]}}
}

使用dis_max:

GET /website/article/_search
{"query": {"dis_max": {"queries": [{"match": {"title": "first article"}},{"match": {"content": "first article"}}]}}
}

(4) tie_breaker

tie_breaker是与dis_max配套使用的. dis_max只取分数最大的那个条件的分数, 完全不考虑其他条件的分数, 但如果在某些场景下也需要考虑其他条件的分数呢? 我们可以指定一个系数值tie_breaker, 将其他条件的分数乘以tie_breaker, 然后和最大分数综合起来计算最终得分.

tie_breaker的取值为 0 ~ 1之间.

a. 将上面的实例优化下:

GET /website/article/_search
{"query": {"dis_max": {"tie_breaker": 0.7, "queries": [{"match": {"title": "first article"}},{"match": {"content": "first article"}}]}}
}

b. 继续优化. 如果搜索词包含多个关键字, 我们要求至少匹配多个关键词, 且多个条件的权重不同.

GET /website/article/_search
{"query": {"dis_max": {"tie_breaker": 0.7, "queries": [{"match": {"title": {"query": "first article hello world","minimum_should_match": "50%","boost": 2}}},{"match": {"content": {"query": "first article is my hero","minimum_should_match": "20%","boost": 1}}}]}}
}
phrase search 短语搜索

(1) 短语搜索, 与全文搜索有什么区别呢?

全文搜索会将"查询词"拆解开来, 去倒排索引中一一匹配, 只要能匹配上任意一个拆解后的关键词, 就可以作为结果返回. 而短语搜索在全文搜索的基础上, 要求关键词必须相邻. (注意短语搜索的"查询词"也是会被分词的)

GET /website/article/_search
{"query": {"match": {"title": "first article"}}
}
//三条记录都会搜索出来GET /website/article/_search
{"query": {"match_phrase": {"title": "first article"}}
}
//只有一条记录

(2) 原理:

短语搜索的原理实际上是相邻匹配(proximity match). Lucene建立的倒排索引结构为: 关键词 -> 文档号, 在文档中的位置, 在文档出现的频率等, 当一个"查询词"包含多个关键词时, Lucene先通过关键词找到对应的文档号, 判断多个关键词所在的文档号是否相同, 然后再判断在文档中的位置是否相邻.

(3) 实例

短语搜索默认是搜索相邻的关键词, 但也可以搜索间隔几个位置的关键词. 间隔越小相关度分数越高.

a. 从content中搜索"first website", first和website必须在同一个doc中, 且间隔不能超过10.

GET /website/article/_search
{"query": {"match_phrase": {"content": {"query": "first website","slop": 10}}}
}

b. 全文搜索和短语搜索配合使用. 从content中搜索"first website", 在优先满足召回率的前提下, 尽可能提高精准度.

召回率: 从n个doc中搜索, 有多少个doc返回.
精准度: 让两个关键词间隔越小的doc相关度分数越高.

GET /website/article/_search
{"query": {"bool": {"must": [{"match": {"content": "first website"}}],"should": [{"match_phrase": {"content": {"query": "first website","slop": 10}}}]}}
}
(4) 优化短语搜索: rescore

短语搜索的性能要比全文搜索的性能低10倍以上, 所以一般我们要用短语搜索时都会配合全文搜索使用. 先通过全文搜索出匹配的doc, 然后对相关度分数最高的前n条doc进行rescore短语搜索. (这里只能用于分页搜索)

GET /website/article/_search
{"query": {"match": {"content": "first website"}},"rescore": {"window_size": 20,"query": {"rescore_query": {"match_phrase": {"content": {"query": "first website","slop": 10}}}}}
}
(5) match_phrase_prefix(搜索推荐)

匹配短语的前缀, 用于做搜索推荐. 比如我们在百度输入一个关键词, 立马就会推荐一系列查询词, 这个就是搜索推荐.

这个功能不推荐使用, 因为性能太差, 我们一般通过ngram分词机制来实现搜索推荐.

GET /website/article/_search
{"query": {"match_phrase_prefix": {"title": "my sec"}}
}

6.1.3.2fuzzy search 模糊搜索

模糊搜索, 自动将拼写错误的搜索文本进行纠正, 然后去匹配索引中的数据.

(1) 语法一

GET /website/article/_search
{"query": {"fuzzy": {"title.keyword": {"value": "my wecond article","fuzziness": 2}}}
}

fuzziness代表最多纠正多少个字母, 默认为2. 搜索文本不会被分词.

(2) 语法二

GET /website/article/_search
{"query": {"match": {"title": {"query": "my wecond article","fuzziness": "auto","operator": "and"}}}
}

fuzziness可以给定个数, 也可以设置为auto.

6.1.3.3term search

term查询, 是一种结构化查询, "查询词"不会被分词, 结果要么存在要么不存在, 不关心结果的score相关度. 如果查询text属性, 需要改为查询filed.keyword.

(1) 实例

和短语搜索对比一下可以更好的理解:

1. phrase搜索
GET /website/article/_search
{"query": {"match_phrase": {"title": "my first article"}}
}
//存在一条结果2. term搜索text
GET /website/article/_search
{"query": {"term": {"title": {"value": "my first article"}}}
}
//不存在结果, 原因是词语查询的value值不会被分词, 也就是直接查询"my first article".3. term搜索keyword
GET /website/article/_search
{"query": {"term": {"title.keyword": {"value": "my first article"}}}
}
//存在一条结果, filed.keyword属性不分词.

(2) 常用语法

为了提高效率, term搜索一般与filter和constant_score联用. constant_score 以固定的评分来执行查询(默认为1), 而filter不计算score相关度, 因此执行效率非常高.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"term": {"post_date": "2017-01-03"}}}}
}

6.1.3.4query filter(过滤数据,)

(1) 语法

query filter 用于过滤数据, 不参与score相关度计算, 效率很高. 适用于范围查询以及不计算相关度score的精确查询(filter + term)

(2) 实例

a. 从website索引中查询, 作者id必须大于等于11402,同时发表时间必须是2017-01-02.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"bool": {"must": [{"term": {"post_date": "2017-01-02"}},{"range": {"author_id": {"gte": 11402}}}]}}}}
}

b. 搜索发布日期为2017-01-01, 或者文章标题为"my first article"的帖子, 同时要求文章的发布日期绝对不为2017-01-02.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"bool": {"should": [{"term":{"post_date": "2017-01-01"}},{"term":{"title.keyword": "my first article"}}],"must_not": {"term": {"post_date": "2017-01-02"}}}}}}
}

c. 搜索文章标题为"my first article", 或者是文章标题为"my second article", 而且发布日期为"2017-01-01"的文章.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"bool": {"should": [{"term":{"title.keyword": "my first article"}},{"bool": {"must": [{"term":{"title.keyword": "my second article"}},{"term":{"post_date": "2017-01-01"}}]}}]}}}}
}

d. 搜索文章标题为"my first article"或"my second article"的文章

GET /website/article/_search
{"query": {"constant_score": {"filter": {"terms": {"title.keyword": ["my first article","my second article"]}}}}
}

e. 搜索tags中包含java的帖子.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"terms": {"tags.keyword": ["java"]}}}}
}

注意, 这里必须用terms, 因为term不支持数组.

d. 搜索tags中只包含java的帖子.

如果想搜索tags中只包含java的帖子, 就需要新增一个字段tags_count, 表示tags中有几个tag, 否则就无法搜索.

GET /website/article/_search
{"query": {"constant_score": {"filter": {"bool": {"must": [{"terms": {"tags.keyword": ["java"]}},{"term": {"tags_count": "1"}}]}}}}
}

对上面这几实例做个总结, should表示或, must表示且.

6.1.4scroll search 滚动数据

scroll滚动搜索,可以先搜索一批数据,然后下次再搜索一批数据,以此类推,直到搜索出全部的数据来. 它的原理是每次查询时都生成一个游标scroll_id, 后续的查询根据这个游标去获取数据, 直到返回的hits字段为空. scroll_id相当于建立了一个历史快照, 在此之后的写操作不会影响到这个快照的结果, 也就意味着其不能用于实时查询.

滚动查询用来解决深度分页的问题, 就类似于sql语句: select * from comment where id > 1000 order by id asc limit 1000.

(1) 语法

  • 查询时指定一个参数scroll, 代表scroll_id的有效期, 过期后scroll_id会被ES自动清除.
  • 如果不需要特定的排序, 按照文档创建时间排序更高效.
  • scroll_id只能使用一次, 使用过后会被自动删除.
  • 最后一次查询, hits为空时也会返回一个scroll_id, 我们需要手动删除来释放资源.

(2) 实例

a. 首次查询

GET /website/article/_search?scroll=1s
{"query": {"match_all": {}},"sort": [{"_doc": {"order": "asc"}}],"size": 1
}

b. 后续查询

scroll_id只能使用一次.

GET /_search/scroll?scroll=1s&scroll_id=DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAATqFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAE6xZkQUNxcFBVa1FMNlR4MlNiOVFkTEZRAAAAAAAABOwWZEFDcXBQVWtRTDZUeDJTYjlRZExGUQAAAAAAAATtFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAE7hZkQUNxcFBVa1FMNlR4MlNiOVFkTEZR
{
}或者GET /_search/scroll
{"scroll":"1s", "scroll_id":"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAATqFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAE6xZkQUNxcFBVa1FMNlR4MlNiOVFkTEZRAAAAAAAABOwWZEFDcXBQVWtRTDZUeDJTYjlRZExGUQAAAAAAAATtFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAE7hZkQUNxcFBVa1FMNlR4MlNiOVFkTEZR"
}

c. 删除指定scroll_id

DELETE /_search/scroll
{"scroll_id": "scroll_id=DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAiXFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAImBZkQUNxcFBVa1FMNlR4MlNiOVFkTEZRAAAAAAAACJkWZEFDcXBQVWtRTDZUeDJTYjlRZExGUQAAAAAAAAiaFmRBQ3FwUFVrUUw2VHgyU2I5UWRMRlEAAAAAAAAImxZkQUNxcFBVa1FMNlR4MlNiOVFkTEZR=="
}
1234

d. 删除所有scroll_id

DELETE /_search/scroll/_all
1

聚合(aggs)

聚合包括分组和统计, 其中分组操作包括term, histogram, date_histogram, filter. 统计操作包括count, avg, max, min, sum, cardinality, percentiles, percentile_ranks等.

注意: 聚合的属性不能被分词.

语法

GET /index/type/_search
{size: 0,"aggs": {"NAME": {"AGG_TYPE": {"field": "field_name"}}}
}

NAME为聚合操作的名称, 可以取一个有参考意义的名称. AGG_TYPE为分组或统计操作, 当进行分组操作时, 会自动生成一个doc_count, 统计了组内数据的数量. 默认按照doc_count降序排列.
size=0的原因是不需要搜索结果, 如果需要搜索结果, 则去除size=0.

实例

(1) 实例数据

新增电视机销售记录, 用于接下来的实例分析.

POST /televisions/sales/_bulk
{ "index": {}}
{ "price" : 1000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-10-28" }
{ "index": {}}
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-11-05" }
{ "index": {}}
{ "price" : 3000, "color" : "绿色", "brand" : "小米", "sold_date" : "2016-05-18" }
{ "index": {}}
{ "price" : 1500, "color" : "蓝色", "brand" : "TCL", "sold_date" : "2016-07-02" }
{ "index": {}}
{ "price" : 1200, "color" : "绿色", "brand" : "TCL", "sold_date" : "2016-08-19" }
{ "index": {}}
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-11-05" }
{ "index": {}}
{ "price" : 8000, "color" : "红色", "brand" : "三星", "sold_date" : "2017-01-01" }
{ "index": {}}
{ "price" : 2500, "color" : "蓝色", "brand" : "小米", "sold_date" : "2017-02-12" }

mapping结构如下:

GET /televisions/_mapping/sales
{"televisions": {"mappings": {"sales": {"properties": {"brand": {"type": "text","fields": {"keyword": {"type": "keyword","ignore_above": 256}}},"color": {"type": "text","fields": {"keyword": {"type": "keyword","ignore_above": 256}}},"price": {"type": "long"},"sold_date": {"type": "date"}}}}}
}

(2) 基础聚合实例

a. 统计哪种颜色的电视销量最高

GET /televisions/sales/_search
{"size": 0,"aggs": {"max_sales_color": {"terms": {"field": "color.keyword"}}}
}

分组后会计算出每组数据个数(doc_count), 默认按照doc_count降序显示.

b. 统计每种颜色电视的平均价格

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_color": {"terms": {"field": "color.keyword"},"aggs": {"avg_price": {"avg": {"field": "price"}}}}}
}

c. 统计每种颜色电视的平均价格, 以及统计每种颜色下每个品牌的平均价格.

这里就涉及到嵌套分组了, 也叫做多层下钻分析.

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_color": {"terms": {"field": "color.keyword"},"aggs": {"color_avg_price": {"avg": {"field": "price"}},"group_by_brand": {"terms": {"field": "brand.keyword"},"aggs": {"brand_avg_price": {"avg": {"field": "price"}}}}}}}
}

d. 统计每种颜色电视机的最大最小价格

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_color": {"terms": {"field": "color.keyword"},"aggs": {"max_price": {"max": {"field": "price"}},"min_price": {"min": {"field": "price"}}}}}
}

e. 统计每种颜色电视机的总销售额

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_color": {"terms": {"field": "color.keyword"},"aggs": {"sum_price": {"sum": {"field": "price"}}}}}
}

(2) 高级聚合实例

a. 按价格区间统计电视销量和销售额

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_price_range": {"histogram": {"field": "price","interval": 2000},"aggs": {"sum_price": {"sum": {"field": "price"}}}}}
}

b. 统计 2016-01-01 ~ 2017-12-31 范围内每个月的电视机销量.

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_sold_date": {"date_histogram": {"field": "sold_date","interval": "month","format": "yyyy-MM-dd","min_doc_count": 0,"extended_bounds": {"min": "2016-01-01","max": "2017-12-31"}}}}
}

c. 统计 2016-01-01 ~ 2017-12-31 范围内每个季度的销售额以及该季度下每个品牌的销售额

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_sold_date": {"date_histogram": {"field": "sold_date","interval": "quarter","format": "yyyy-MM-dd","min_doc_count": 0,"extended_bounds": {"min": "2016-01-01","max": "2017-12-31"}},"aggs": {"sum_price": {"sum": {"field": "price"}},"group_by_brand": {"terms": {"field": "brand.keyword"},"aggs": {"brand_sum_price": {"sum": {"field": "price"}}}}}}}
}

d. 统计每种颜色电视的销售额, 按照销售额升序排序

GET /televisions/sales/_search
{"size": 0, "aggs": {"group_by_color": {"terms": {"field": "color.keyword","order": {"sum_price": "asc"}},"aggs": {"sum_price": {"sum": {"field": "price"}}}}}
}

e. 统计每种颜色下的每个品牌电视机的总销售额, 并按这个销售额升序排序.

GET /televisions/sales/_search
{"size": 0, "aggs": {"group_by_color": {"terms": {"field": "color.keyword"},"aggs": {"group_by_brand": {"terms": {"field": "brand.keyword","order": {"color_brand_sum_price": "asc"}},"aggs": {"color_brand_sum_price": {"sum": {"field": "price"}}}}}}}
}

f. 统计每个月的电视销量, 并按品牌去重.

GET /televisions/sales/_search
{"size": 0, "aggs": {"group_by_sold_date": {"date_histogram": {"field": "sold_date","interval": "month","format": "yyyy-MM-dd"},"aggs": {"distinct_brand": {"cardinality": {"field": "brand.keyword","precision_threshold": 100 }}}}}
}

cardinality 去重采用的是近似估计的算法, 错误率在5%左右, 其中precision_threshold指定的值为100%准确去重的数量, 值设置的越大, 内存开销也就越大.

g. 统计50%, 90% 和 99%的电视的最大价格(一般用于统计api请求的最长延迟时间)

GET /televisions/sales/_search
{"size": 0, "aggs": {"price_percentiles": {"percentiles": {"field": "price","percents": [50,90,99]}}}
}

h. 统计每个品牌的电视机的价格, 在1000以内, 2000以内, 3000以内, 4000以内的所占比例.

GET /televisions/sales/_search
{"size": 0,"aggs": {"group_by_brand": {"terms": {"field": "brand.keyword"},"aggs": {"price_percentile_ranks": {"percentile_ranks": {"field": "price","values": [1000,2000,3000,4000]}}}}}
}

(3) 搜索+聚合

a. 统计指定品牌下(小米)每个颜色的销量

GET /televisions/sales/_search
{"size": 0, "query": {"term": {"brand.keyword": {"value": "小米"}}}, "aggs": {"group_by_color": {"terms": {"field": "color.keyword"}}}
}

或者

GET /televisions/sales/_search
{"size": 0, "query": {"constant_score": {"filter": {"term": {"brand.keyword": "小米"}}}}, "aggs": {"group_by_color": {"terms": {"field": "color.keyword"}}}
}

其实对于聚合来说, 因为不需要搜索结果, 可以直接用filter, 效率更高.

b. 统计单个品牌(长虹)与所有品牌销售额对比

GET /televisions/sales/_search
{"size": 0, "query": {"constant_score": {"filter": {"term": {"brand.keyword": "长虹"}}}}, "aggs": {"single_brand_sum_price": {"sum": {"field": "price"}},"all_brand": {"global": {},"aggs": {"all_brand_sum_price": {"sum": {"field": "price"}}}}}
}

global 表示将所有数据纳入聚合的scope,忽视前面的query过滤.

c. 统计指定品牌(长虹)最近一个月和最近半年的平均价格

GET /televisions/sales/_search
{"size": 0, "query": {"term": {"brand.keyword": {"value": "长虹"}}}, "aggs": {"recent_one_month": {"filter": {"range": {"sold_date": {"gte": "now-1M"}}},"aggs": {"recent_one_month_avg_price": {"avg": {"field": "price"}}}},"recent_six_month": {"filter": {"range": {"sold_date": {"gte": "now-6M"}}},"aggs": {"recent_six_month_avg_price": {"avg": {"field": "price"}}}}}
}

[^ElasticSearch Rest API思维导图,详见附件1,附件2]:

6.2 C#操作库

官方链接

我这里用的是6.x.

简单的查询和插入

using Elasticsearch.Net;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;public class ElascticsearchDemo{private ElasticLowLevelClient lowlevelClient;public ElascticsearchDemo(){Init();}public void Init(){var settings = new ConnectionConfiguration(new Uri("http://127.0.0.1:9200")).RequestTimeout(TimeSpan.FromMinutes(2));lowlevelClient = new ElasticLowLevelClient(settings);}/// <summary>/// 插入 指定Id/// </summary>public byte[] Insert<T>(T obj,string Id) where T:class{var indexResponse = lowlevelClient.Index<BytesResponse>("people", "person", "1", PostData.Serializable(obj));byte[] responseBytes = indexResponse.Body;return responseBytes;}/// <summary>/// Insert 可以不指定Id/// </summary>public  async Task<string> Insert<T>(T obj) where T : class{var asyncIndexResponse = await lowlevelClient.IndexAsync<StringResponse>("people", "person", PostData.Serializable(obj));string responseJson = asyncIndexResponse.Body;return responseJson;}public async Task<string> Search(dynamic data){var searchResponse = await lowlevelClient.SearchAsync<StringResponse>("people", "person", PostData.Serializable(data));var successful = searchResponse.Success;var responseJson = searchResponse.Body;return responseJson;}

启动项

    class Program{static void Main(string[] args){ElascticsearchDemo elascticsearchDemo = new ElascticsearchDemo();//插入两种方式Insert1(elascticsearchDemo);Insert2(elascticsearchDemo);///SearchingSearch(elascticsearchDemo);}private static void Insert2(ElascticsearchDemo elascticsearchDemo){//插入Person person = new Person{name = "sunny",age = 15,sex = "女"};string json = elascticsearchDemo.Insert(person).Result;Console.WriteLine(json);}private static void Insert1(ElascticsearchDemo elascticsearchDemo){//插入Person obj = new Person{id = 9999,name = "james",age = 16,sex = "男"};byte[] bytes = elascticsearchDemo.Insert(obj, "9999");}private static void Search(ElascticsearchDemo elascticsearchDemo){//查询dynamic obj = new{from = 0,size = 10,query = new{match = new{name = "james"}}};string json = elascticsearchDemo.Search(obj).Result;Console.WriteLine(json);}
    class Person{public int id { get; set; }public string name { get; set; }public int age { get; set; }public string sex { get; set; }}
}

6.3 JAVA 类库

官方链接

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>6.5.4</version>
</dependency>

和.Net类似不再做详细介绍

6 Es 的坑

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-crGREfei-1608803935855)(H:\doc\markdown\404126-20181113154043693-363565967.png)]

7.其他

7.1elasticsearch写入数据原理?

7.2倒排索引实现原理

8.elasticsearch相关面试题

1、elasticsearch了解多少,说说你们公司es的集群架构,索引数据大小,分片有多少,以及一些调优手段 。

面试官:想了解应聘者之前公司接触的ES使用场景、规模,有没有做过比较大规模的索引设计、规划、调优。
解答
如实结合自己的实践场景回答即可。
比如:ES集群架构13个节点,索引根据通道不同共20+索引,根据日期,每日递增20+,索引:10分片,每日递增1亿+数据,
每个通道每天索引大小控制:150GB之内。

仅索引层面调优手段:

1.1、设计阶段调优

  • 1)根据业务增量需求,采取基于日期模板创建索引,通过roll over API滚动索引;
  • 2)使用别名进行索引管理;
  • 3)每天凌晨定时对索引做force_merge操作,以释放空间;
  • 4)采取冷热分离机制,热数据存储到SSD,提高检索效率;冷数据定期进行shrink操作,以缩减存储;
  • 5)采取curator进行索引的生命周期管理;
  • 6)仅针对需要分词的字段,合理的设置分词器;
  • 7)Mapping阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。 …

1.2、写入调优

  • 1)写入前副本数设置为0;
  • 2)写入前关闭refresh_interval设置为-1,禁用刷新机制;
  • 3)写入过程中:采取bulk批量写入;
  • 4)写入后恢复副本数和刷新间隔;
  • 5)尽量使用自动生成的id。

1.3、查询调优

  • 1)禁用wildcard;
  • 2)禁用批量terms(成百上千的场景);
  • 3)充分利用倒排索引机制,能keyword类型尽量keyword;
  • 4)数据量大时候,可以先基于时间敲定索引再检索;
  • 5)设置合理的路由机制。

1.4、其他调优

部署调优,业务调优等。

上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。

2、elasticsearch的倒排索引是什么?

面试官:想了解你对基础概念的认知。
解答:通俗解释一下就可以。

传统的我们的检索是通过文章,逐个遍历找到对应关键词的位置。
而倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为倒排索引。
有了倒排索引,就能实现o(1)时间复杂度的效率检索文章了,极大的提高了检索效率。

学术的解答方式:

倒排索引,相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。

加分项:倒排索引的底层实现是基于:FST(Finite State Transducer)数据结构。
lucene从4+版本后开始大量使用的数据结构是FST。FST有两个优点:

  • 1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;
  • 2)查询速度快。O(len(str))的查询时间复杂度。

3、elasticsearch 索引数据多了怎么办,如何调优,部署?

面试官:想了解大数据量的运维能力。
解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。
如何调优,正如问题1所说,这里细化一下:

3.1 动态索引层面

基于模板+时间+rollover api滚动创建索引,举例:设计阶段定义:blog索引的模板格式为:blog_index_时间戳的形式,每天递增数据。

这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线2的32次幂-1,索引存储达到了TB+甚至更大。

一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。

3.2 存储层面

冷热数据分离存储,热数据(比如最近3天或者一周的数据),其余为冷数据。
对于冷数据不会再写入新数据,可以考虑定期force_merge加shrink压缩操作,节省存储空间和检索效率。

3.3 部署层面

一旦之前没有规划,这里就属于应急策略。
结合ES自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。

4、elasticsearch是如何实现master选举的?

面试官:想了解ES集群的底层原理,不再只关注业务层面了。
解答
前置前提:

  • 1)只有候选主节点(master:true)的节点才能成为主节点。
  • 2)最小主节点数(min_master_nodes)的目的是防止脑裂。

这个我看了各种网上分析的版本和源码分析的书籍,云里雾里。
核对了一下代码,核心入口为findMaster,选择主节点成功返回对应Master,否则返回null。选举流程大致描述如下:

  • 第一步:确认候选主节点数达标,elasticsearch.yml设置的值discovery.zen.minimum_master_nodes;
  • 第二步:比较:先判定是否具备master资格,具备候选主节点资格的优先返回;若两节点都为候选主节点,则id小的值会主节点。注意这里的id为string类型。

题外话:获取节点id的方法。

GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
ip        port heapPercent heapMax id   name
127.0.0.1 9300          39   1.9gb Hk9w Hk9wFwU
123

5、详细描述一下Elasticsearch索引文档的过程?

面试官:想了解ES的底层原理,不再只关注业务层面了。
解答
这里的索引文档应该理解为文档写入ES,创建索引的过程。
文档写入包含:单文档写入和批量bulk写入,这里只解释一下:单文档写入流程。

记住官方文档中的这个图。

第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演路由节点的角色。)

第二步:节点1接受到请求后,使用文档_id来确定文档属于分片0。请求会被转到另外的节点,假定节点3。因此分片0的主分片分配到节点3上。

第三步:节点3在主分片上执行写操作,如果成功,则将请求并行转发到节点1和节点2的副本分片上,等待结果返回。所有的副本分片都报告成功,节点3将向协调节点(节点1)报告成功,节点1向请求客户端报告写入成功。

如果面试官再问:第二步中的文档获取分片的过程?
回答:借助路由算法获取,路由算法就是根据路由和文档id计算目标的分片id的过程。

shard = hash(_routing) % (num_of_primary_shards)
1

6、详细描述一下Elasticsearch搜索的过程?

面试官:想了解ES搜索的底层原理,不再只关注业务层面了。
解答
搜索拆解为“query then fetch” 两个阶段。
query阶段的目的:定位到位置,但不取。
步骤拆解如下:

  • 1)假设一个索引数据有5主+1副本 共10分片,一次请求会命中(主或者副本分片中)的一个。
  • 2)每个分片在本地进行查询,结果返回到本地有序的优先队列中。
  • 3)第2)步骤的结果发送到协调节点,协调节点产生一个全局的排序列表。

fetch阶段的目的:取数据。
路由节点获取所有文档,返回给客户端。

7、Elasticsearch在部署时,对Linux的设置有哪些优化方法?

面试官:想了解对ES集群的运维能力。
解答

  • 1)关闭缓存swap;
  • 2)堆内存设置为:Min(节点内存/2, 32GB);
  • 3)设置最大文件句柄数;
  • 4)线程池+队列大小根据业务需要做调整;
  • 5)磁盘存储raid方式——存储有条件使用RAID10,增加单节点性能以及避免单节点存储故障。

8、lucence内部结构是什么?

面试官:想了解你的知识面的广度和深度。
解答

Lucene是有索引和搜索的两个过程,包含索引创建,索引,搜索三个要点。可以基于这个脉络展开一些。

#小结
看到题目后,感觉熟悉又陌生。真正要在面试的时候讲出来,需要下一番功夫深入理解。
为了求证回答的相对准确性,我翻看了源码、官方文档和部分有深度的博文。
Elasticsearch路还很长,别无他法,唯有死磕!

9.客户端在和集群连接时,如何选择特定的节点执行请求的?

TransportClient 利用 transport 模块远程连接一个 elasticsearch 集群。它并不加入到集群中,只是简单的获得一个或者多个初始化的 transport 地址,并以 轮询 的方式与这些地址进行通信。

10.详细描述一下 Elasticsearch 索引文档的过程。

协调节点默认使用文档 ID 参与计算(也支持通过 routing),以便为路由提供合适的分片。

shard = hash(document_id) % (num_of_primary_shards)

(1)当分片所在的节点接收到来自协调节点的请求后,会将请求写入到 MemoryBuffer,然后定时(默认是每隔 1 秒)写入到 Filesystem Cache,这个从 MomeryBuffer 到 Filesystem Cache 的过程就叫做 refresh;

(2)当然在某些情况下,存在 Momery Buffer 和 Filesystem Cache 的数据可能会丢失,ES 是通过 translog 的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到 translog 中 ,当 Filesystem cache 中的数据写入到磁盘中时,才会清除掉,这个过程叫做 flush;

(3)在 flush 过程中,内存中的缓冲将被清除,内容被写入一个新段,段的 fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的 translog 将被删除并开始一个新的 translog。

(4)flush 触发的时机是定时触发(默认 30 分钟)或者 translog 变得太大(默认为 512M)时;

补充:关于 Lucene 的 Segement:

(1)Lucene 索引是由多个段组成,段本身是一个功能齐全的倒排索引。

(2)段是不可变的,允许 Lucene 将新的文档增量地添加到索引中,而不用从头重建索引。

(3)对于每一个搜索请求而言,索引中的所有段都会被搜索,并且每个段会消耗CPU 的时钟周、文件句柄和内存。这意味着段的数量越多,搜索性能会越低。

(4)为了解决这个问题,Elasticsearch 会合并小段到一个较大的段,提交新的合并段到磁盘,并删除那些旧的小段。

11、详细描述一下 Elasticsearch 更新和删除文档的过程。

(1)删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更;

(2)磁盘上的每个段都有一个相应的.del 文件。当删除请求发送后,文档并没有真的被删除,而是在.del 文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在.del 文件中被标记为删除的文档将不会被写入新段。

(3)在新的文档被创建时,Elasticsearch 会为该文档指定一个版本号,当执行更新时,旧版本的文档在.del 文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。

12、在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的?

(1)Lucene的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。

(2)Lucene的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。

13、Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?

(1)64 GB 内存的机器是非常理想的, 但是 32 GB 和 16 GB 机器也是很常见的。少于 8 GB 会适得其反。

(2)如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。

(3)如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。

(4)即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。

(5)请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在Elasticsearch 的几个地方,使用 Java 的本地序列化。

(6)通过设置 gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time 可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。

(7)Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。

(8)不要随意修改垃圾回收器(CMS)和各个线程池的大小。

(9)把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE 环境变量设置。

(10)内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。

(11)Lucene 使用了大 量 的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。

补充:索引阶段性能提升方法

(1)使用批量请求并调整其大小:每次批量数据 5–15 MB 大是个不错的起始点。

(2)存储:使用 SSD

(3)段和合并:Elasticsearch 默认值是 20 MB/s,对机械磁盘应该是个不错的设置。如果你用的是 SSD,可以考虑提高到 100–200 MB/s。如果你在做批量导入,完全不在意搜索,你可以彻底关掉合并限流。另外还可以增加index.translog.flush_threshold_size 设置,从默认的 512 MB 到更大一些的值,比如 1 GB,这可以在一次清空触发的时候在事务日志里积累出更大的段。

(4)如果你的搜索结果不需要近实时的准确度,考虑把每个索引的index.refresh_interval 改到 30s。

(5)如果你在做大批量导入,考虑通过设置 index.number_of_replicas: 0 关闭副本。

14、Elasticsearch 对于大数据量(上亿量级)的聚合如何实现?

Elasticsearch 提供的首个近似聚合是 cardinality 度量。它提供一个字段的基数,即该字段的 distinct 或者 unique 值的数目。它是基于 HLL 算法的。HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 = 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关。

15、在并发情况下,Elasticsearch 如果保证读写一致?

(1)可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突;

(2)另外对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。

(3)对于读操作,可以设置 replication 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置 replication 为 async 时,也可以通过设置搜索请求参数_preference 为 primary 来查询主分片,确保文档是最新版本。

16、如何监控 Elasticsearch 集群状态?

Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。

17、介绍下你们电商搜索的整体技术架构。

18、介绍一下你们的个性化搜索方案?

基于word2vec和Elasticsearch实现个性化搜索

(1)基于word2vec、Elasticsearch和自定义的脚本插件,我们就实现了一个个性化的搜索服务,相对于原有的实现,新版的点击率和转化率都有大幅的提升;

(2)基于word2vec的商品向量还有一个可用之处,就是可以用来实现相似商品的推荐;

(3)使用word2vec来实现个性化搜索或个性化推荐是有一定局限性的,因为它只能处理用户点击历史这样的时序数据,而无法全面的去考虑用户偏好,这个还是有很大的改进和提升的空间;

19、是否了解字典树?

常用字典数据结构如下所示:

Trie 的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。它有 3 个基本性质:

1)根节点不包含字符,除根节点外每一个节点都只包含一个字符。

2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

3)每个节点的所有子节点包含的字符都不相同。

(1)可以看到,trie 树每一层的节点数是 26^i 级别的。所以为了节省空间,我们还可以用动态链表,或者用数组来模拟动态。而空间的花费,不会超过单词数×单词长度。

(2)实现:对每个结点开一个字母集大小的数组,每个结点挂一个链表,使用左儿子右兄弟表示法记录这棵树;

(3)对于中文的字典树,每个节点的子节点用一个哈希表存储,这样就不用浪费太大的空间,而且查询速度上可以保留哈希的复杂度 O(1)。

20、拼写纠错是如何实现的?

(1)拼写纠错是基于编辑距离来实现;编辑距离是一种标准的方法,它用来表示经过插入、删除和替换操作从一个字符串转换到另外一个字符串的最小操作步数;

(2)编辑距离的计算过程:比如要计算 batyu 和 beauty 的编辑距离,先创建一个7×8 的表(batyu 长度为 5,coffee 长度为 6,各加 2),接着,在如下位置填入黑色数字。其他格的计算过程是取以下三个值的最小值:

如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字+1。(对于 3,3 来说为 0)

左方数字+1(对于 3,3 格来说为 2)

上方数字+1(对于 3,3 格来说为 2)

最终取右下角的值即为编辑距离的值 3。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zERdnTkS-1608803935858)(H:\doc\markdown\v2-57fb52790c10465912f9e608703d7497_hd.jpg)]

对于拼写纠错,我们考虑构造一个度量空间(Metric Space),该空间内任何关系满足以下三条基本条件:

d(x,y) = 0 – 假如 x 与 y 的距离为 0,则 x=y

d(x,y) = d(y,x) – x 到 y 的距离等同于 y 到 x 的距离

d(x,y) + d(y,z) >= d(x,z) – 三角不等式

(1)根据三角不等式,则满足与 query 距离在 n 范围内的另一个字符转 B,其与 A的距离最大为 d+n,最小为 d-n。

(2)BK 树的构造就过程如下:每个节点有任意个子节点,每条边有个值表示编辑距离。所有子节点到父节点的边上标注 n 表示编辑距离恰好为 n。比如,我们有棵树父节点是”book”和两个子节点”cake”和”books”,”book”到”books”的边标号 1,”book”到”cake”的边上标号 4。从字典里构造好树后,无论何时你想插入新单词时,计算该单词与根节点的编辑距离,并且查找数值为d(neweord, root)的边。递归得与各子节点进行比较,直到没有子节点,你就可以创建新的子节点并将新单词保存在那。比如,插入”boo”到刚才上述例子的树中,我们先检查根节点,查找 d(“book”, “boo”) = 1 的边,然后检查标号为1 的边的子节点,得到单词”books”。我们再计算距离 d(“books”, “boo”)=2,则将新单词插在”books”之后,边标号为 2。

(3)查询相似词如下:计算单词与根节点的编辑距离 d,然后递归查找每个子节点标号为 d-n 到 d+n(包含)的边。假如被检查的节点与搜索单词的距离 d 小于 n,则返回该节点并继续查询。比如输入 cape 且最大容忍距离为 1,则先计算和根的编辑距离 d(“book”, “cape”)=4,然后接着找和根节点之间编辑距离为 3 到5 的,这个就找到了 cake 这个节点,计算 d(“cake”, “cape”)=1,满足条件所以返回 cake,然后再找和 cake 节点编辑距离是 0 到 2 的,分别找到 cape 和cart 节点,这样就得到 cape 这个满足条件的结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-73LDpmTQ-1608803935858)(H:\doc\markdown\v2-414dc1cfe3428df85f5d947a793e9505_hd.jpg)]

鸣谢:

1. 终于有人把Elasticsearch原理讲透了!

2.ElasticSearch Rest API 一文全搞定

3.elasticsearch面试必考(亲身经历的问题)

4《死磕 Elasticsearch 方法论》:普通程序员高效精进的 10 大狠招!(完整版)

附图

附图1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9pAN04A6-1608803935859)(H:\doc\markdown\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdGlhbnhpYW5nX2thb2xh,size_16,color_FFFFFF,t_70)]

附图2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPYNgdwG-1608803935859)(H:\doc\markdown\ElasticSearch-learn.png)]

Elasticsearch一网打通相关推荐

  1. EVE-NG--华为防火墙USG6000v 内外网打通,并均可通过公网IP访问FTP服务器

    EVE-NG–华为防火墙USG6000v 内外网打通,并均可通过公网IP访问FTP服务器 所有镜像在EVE-NG第一个博客百度云链接里面,自行下载. 需要现成自制镜像的私信我,百度云盘无偿分享给你. ...

  2. elasticsearch外网访问

    为什么80%的码农都做不了架构师?>>>    elasticsearch5.2.1 外网访问配置 transport.host: localhost transport.tcp.p ...

  3. Elasticsearch外网无法通过ip访问

    目录 1 遇到的问题 2 解决方法 1 遇到的问题 外网服务器安装 elasticsearch,解压elasticsearch之后,启动,通过 http://localhost:9200 可以访问的到 ...

  4. MAC下安装ElasticSearch(官网下载安装包)

    1.基础环境准备 Elasticsearch 依赖于JDK, 并且JDK 版本1.8+ 检验jdk  命令 : java -version 2.下载安装包 去官网下载https://www.elast ...

  5. 解决Elasticsearch外网访问的问题(楼主亲测)

    以前我将Elasticsearch安装在自己的机器上,但是每天开关机比较麻烦. 后来买了一台云服务器. 一.外网访问问题 默认情况下,是不支持外网访问,如果你的Elasticsearch安装在其他机器 ...

  6. ElasticSearch 慕课网(一)

    第一章 ElasticSearch 和 kibana 入门 第一节  ElasticSearch 的安装与运行 1.下载 jdk 1.8 版本 https://www.oracle.com/techn ...

  7. 【Elasticsearch】Elasticsearch-Hadoop打通Elasticsearch和Hadoop

    https://elasticsearch.cn/article/6194

  8. Holer实现外网访问本地Elasticsearch

    外网访问内网Elasticsearch 内网主机上安装了Elasticsearch,只能在局域网内访问,怎样从公网也能访问本地Elasticsearch? 本文将介绍使用holer实现的具体步骤. 1 ...

  9. 「测评系列之少数派」打通 IM 和日历,飞书重新定义文档

    早在去年,少数派就受邀内测,率先体验了字节跳动出品的办公套件「飞书」.经过一段时间使用,我们发现它将 IM.文档协作和日程安排做了很好地结合,整体结构和设计细节上也非常人性化,所以最终决定将公司的日常 ...

最新文章

  1. 点云配准求物体的6D姿态(转)
  2. 用jar命令将Web应用打包成war文件的简单方法
  3. 【主机】vnc 介绍以及安装时注意的问题
  4. [转]12种JavaScript MVC框架之比较
  5. java.lang.NoClassDefFoundError: javax/xml/bind/ValidationException
  6. windows下利用IIS搭建web和ftp服务以及防火墙配置
  7. C# DateTime日期格式
  8. 百度云 api java_java实现百度云文字识别接口代码
  9. sqlserver无ldf日志文件附加的方法(数据库没有完全关闭,无法重新生成日志)...
  10. 什么是腾讯云图数据可视化?它有哪些特性以及应用场景?
  11. 【Java】NIO 仿照zookeeper 写的 nio客户端
  12. springboot获取视频时长以及截取视频第一帧
  13. GO的lua虚拟机 gopher-lua
  14. 如何推广自己的新网站
  15. 创业失败的工程师内心依旧有代码
  16. 调出cmd输入时的光标
  17. 沈理工大学计算机设计专业,沈理工学子在全国大学生计算机设计竞赛中喜获佳绩...
  18. 面试题HTML +CSS
  19. 开发板------OK6410
  20. 9008刷机模式写入超时刷机帮_高通9008刷机大法,避坑指南,救砖前提

热门文章

  1. WSN(1):第一章  绪论
  2. Windows系统下R语言环境搭建及高级图表绘制
  3. Study16 面向对象三大特性
  4. 用计算机能改装成万用表吗,电脑机箱风扇改装成DIY空调扇USB风扇
  5. 灰色预测模型【GM(1,1)模型】 【matlab代码】
  6. FCBF算法的Matlab实现
  7. OpenCV色彩空间类型
  8. mysql备份用户权限【转】
  9. 微信小程序实现运动步数排行(可删除)
  10. 二维三维四维vector乃至多维vector数组的建立