
- 所属公司
- 上海英模特制衣有限公司
- 所属行业
- 服饰
- 中文名称
- ES服饰
- 创立时间
- 1994
- 英文名称
- etamsports
-
ES基本介绍
2019-06-28 16:10:23ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎。 同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储...简介
ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎。
同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储以及处理PB级的数据。
可以在极短的时间内存储、搜索和分析大量的数据。通常作为具有复杂搜索场景情况下的核心发动机。
ES就是为高可用和可扩展而生的。一方面可以通过升级硬件来完成系统扩展,称为垂直或向上扩展(Vertical Scale/Scaling Up)。
另一方面,增加更多的服务器来完成系统扩展,称为水平扩展或者向外扩展(Horizontal Scale/Scaling Out)。尽管ES能够利用更强劲的硬件,但是垂直扩展毕竟还是有它的极限。真正的可扩展性来自于水平扩展,通过向集群中添加更多的节点来分担负载,增加可靠性。ES天生就是分布式的,它知道如何管理多个节点来完成扩展和实现高可用性。意味应用不需要做任何的改动。
Gateway,代表ES索引的持久化存储方式。在Gateway中,ES默认先把索引存储在内存中,然后当内存满的时候,再持久化到Gateway里。当ES集群关闭或重启的时候,它就会从Gateway里去读取索引数据。比如LocalFileSystem和HDFS、AS3等。
DistributedLucene Directory,它是Lucene里的一些列索引文件组成的目录。它负责管理这些索引文件。包括数据的读取、写入,以及索引的添加和合并等。
River,代表是数据源。是以插件的形式存在于ES中。
Mapping,映射的意思,非常类似于静态语言中的数据类型。比如我们声明一个int类型的变量,那以后这个变量只能存储int类型的数据。比如我们声明一个double类型的mapping字段,则只能存储double类型的数据。
Mapping不仅是告诉ES,哪个字段是哪种类型。还能告诉ES如何来索引数据,以及数据是否被索引到等。
Search Moudle,搜索模块,支持搜索的一些常用操作
Index Moudle,索引模块,支持索引的一些常用操作
Disvcovery,主要是负责集群的master节点发现。比如某个节点突然离开或进来的情况,进行一个分片重新分片等。这里有个发现机制。
发现机制默认的实现方式是单播和多播的形式,即Zen,同时也支持点对点的实现。另外一种是以插件的形式,即EC2。
Scripting,即脚本语言。包括很多,这里不多赘述。如mvel、js、python等。
Transport,代表ES内部节点,代表跟集群的客户端交互。包括 Thrift、Memcached、Http等协议
RESTful Style API,通过RESTful方式来实现API编程。
3rd plugins,代表第三方插件。
Java(Netty),是开发框架。
JMX,是监控。
使用案例
1、将ES作为网站的主要后端系统
比如现在搭建一个博客系统,对于博客帖子的数据可以直接在ES上存储,并且使用ES来进行检索,统计。ES提供了持久化的存储、统计和很多其他数据存储的特性。
注意:但是像其他的NOSQL数据存储一样,ES是不支持事务的,如果要事务机制,还是考虑使用其他的数据库做真实库。
2、将ES添加到现有系统
有些时候不需要ES提供所有数据的存储功能,只是想在一个数据存储的基础之上使用ES。比如已经有一个复杂的系统在运行,但是现在想加一个搜索的功能,就可以使用该方案。
3、将ES作为现有解决方案的后端部分
因为ES是开源的系统,提供了直接的HTTP接口,并且现在有一个大型的生态系统在支持他。比如现在我们想部署大规模的日志框架、用于存储、搜索和分析海量的事件,考虑到现有的工具可以写入和读取ES,可以不需要进行任何开发,配置这些工具就可以去运作。
设计结构
1、逻辑设计
文档
文档是可以被索引的信息的基本单位,它包含几个重要的属性:
- 是自我包含的。一篇文档同时包含字段和他们的取值。
- 是层次型的。文档中还可以包含新的文档,一个字段的取值可以是简单的,例如location字段的取值可以是字符串,还可以包含其他字段和取值,比如可以同时包含城市和街道地址。
- 拥有灵活的结构。文档不依赖于预先定义的模式。也就是说并非所有的文档都需要拥有相同的字段,并不受限于同一个模式
{
"name":"meeting",
"location":"office",
"organizer":"yanping"
}
{
"name":"meeting",
"location":{
"name":"sheshouzuo",
"date":"2019-6-28"
},
"memebers":["leio","shiyi"]
}
类型
类型是文档的逻辑容器,类似于表格是行的容器。在不同的类型中,最好放入不同的结构的文档。
字段
ES中,每个文档,其实是以json形式存储的。而一个文档可以被视为多个字段的集合。
映射
每个类型中字段的定义称为映射。例如,name字段映射为String。
索引
索引是映射类型的容器一个ES的索引非常像关系型世界中的数据库,是独立的大量文档集合。
关系型数据库与ES的结构上的对比
2、物理设计
节点
一个节点是一个ES的实例,在服务器上启动ES之后,就拥有了一个节点,如果在另一个服务器上启动ES,这就是另一个节点。甚至可以在一台服务器上启动多个ES进程,在一台服务器上拥有多个节点。多个节点可以加入同一个集群。
当ElasticSearch的节点启动后,它会利用多播(multicast)(或者单播,如果用户更改了配置)寻找集群中的其它节点,并与之建立连接。这个过程如下图所示:
节点主要有3种类型,第一种类型是client_node,主要是起到请求分发的作用,类似路由。第二种类型是master_node,是主的节点,所有的新增,删除,数据分片都是由主节点操作(elasticsearch底层是没有更新数据操作的,上层对外提供的更新实际上是删除了再新增),当然也能承担搜索操作。第三种类型是date_node,该类型的节点只能做搜索操作,具体会分配到哪个date_node,就是由client_node决定,而data_node的数据都是从master_node同步过来的
分片
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。
为了解决这个问题,ES提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因:
1、允许你水平分割/扩展你的内容容量
允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由ES管理的,对于作为用户的你来说,这些都是透明的。
2、在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了。这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,ES允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,主要有两方面的原因:
(1)在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
(2)扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制数量,但是不能改变分片的数量。
默认情况下,ES中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。一个索引的多个分片可以存放在集群中的一台主机上,也可以存放在多台主机上,这取决于你的集群机器数量。主分片和复制分片的具体位置是由ES内在的策略所决定的。
3、插件HEAD
elasticsearch-head是一个界面化的集群操作和管理工具
● node:即一个 Elasticsearch 的运行实例,使用多播或单播方式发现 cluster 并加入。
● cluster:包含一个或多个拥有相同集群名称的 node,其中包含一个master node。
● index:类比关系型数据库里的DB,是一个逻辑命名空间。
● alias:可以给 index 添加零个或多个alias,通过 alias 使用index 和根据index name 访问index一样,但是,alias给我们提供了一种切换index的能力,比如重建了index,取名● customer_online_v2,这时,有了alias,我要访问新 index,只需要把 alias 添加到新 index 即可,并把alias从旧的 index 删除。不用修改代码。
● type:类比关系数据库里的Table。其中,一个index可以定义多个type,但一般使用习惯仅配一个type。
● mapping:类比关系型数据库中的 schema 概念,mapping 定义了 index 中的 type。mapping 可以显示的定义,也可以在 document 被索引时自动生成,如果有新的 field,Elasticsearch 会自动推测出 field 的type并加到mapping中。
● document:类比关系数据库里的一行记录(record),document 是 Elasticsearch 里的一个 JSON 对象,包括零个或多个field。
● field:类比关系数据库里的field,每个field 都有自己的字段类型。
● shard:是一个Lucene 实例。Elasticsearch 基于 Lucene,shard 是一个 Lucene 实例,被 Elasticsearch 自动管理。之前提到,index 是一个逻辑命名空间,shard 是具体的物理概念,建索引、查询等都是具体的shard在工作。shard 包括primary shard 和 replica shard,写数据时,先写到primary shard,然后,同步到replica shard,查询时,primary 和 replica 充当相同的作用。replica shard 可以有多份,也可以没有,replica shard的存在有两个作用,一是容灾,如果primary shard 挂了,数据也不会丢失,集群仍然能正常工作;二是提高性能,因为replica 和 primary shard 都能处理查询。另外,如上图右侧红框所示,shard数和replica数都可以设置,但是,shard 数只能在建立index 时设置,后期不能更改,但是,replica 数可以随时更改。但是,由于 Elasticsearch 很友好的封装了这部分,在使用Elasticsearch 的过程中,我们一般仅需要关注 index 即可,不需关注shard。
shard、node、cluster 在物理上构成了 Elasticsearch 集群,field、type、index 在逻辑上构成一个index的基本概念,在使用 Elasticsearch 过程中,我们一般关注到逻辑概念就好,就像我们在使用MySQL 时,我们一般就关注DB Name、Table和schema即可,而不会关注DBA维护了几个MySQL实例、master 和 slave 等怎么部署的一样。
ES中的索引原理
(1)传统的关系型数据库
二叉树查找效率是logN,同时插入新的节点不必移动全部节点,所以用树型结构存储索引,能同时兼顾插入和查询的性能。因此在这个基础上,再结合磁盘的读取特性(顺序读/随机读),传统关系型数据库采用了B-Tree/B+Tree这样的数据结构做索引
(2)ES
采用倒排索引
那么,倒排索引是个什么样子呢?
首先,来搞清楚几个概念,为此,举个例子:
假设有个user索引,它有四个字段:分别是name,gender,age,address。画出来的话,大概是下面这个样子,跟关系型数据库一样
Term(单词):一段文本经过分析器分析以后就会输出一串单词,这一个一个的就叫做Term
Term Dictionary(单词字典):顾名思义,它里面维护的是Term,可以理解为Term的集合
Term Index(单词索引):为了更快的找到某个单词,我们为单词建立索引
Posting List(倒排列表):倒排列表记录了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。(PS:实际的倒排列表中并不只是存了文档ID这么简单,还有一些其它的信息,比如:词频(Term出现的次数)、偏移量(offset)等,可以想象成是Python中的元组,或者Java中的对象)
(PS:如果类比现代汉语词典的话,那么Term就相当于词语,Term Dictionary相当于汉语词典本身,Term Index相当于词典的目录索引)
我们知道,每个文档都有一个ID,如果插入的时候没有指定的话,Elasticsearch会自动生成一个,因此ID字段就不多说了
上面的例子,Elasticsearch建立的索引大致如下:
name字段:
age字段:
gender字段:
address字段:
Elasticsearch分别为每个字段都建立了一个倒排索引。比如,在上面“张三”、“北京市”、22 这些都是Term,而[1,3]就是Posting List。Posting list就是一个数组,存储了所有符合某个Term的文档ID。
只要知道文档ID,就能快速找到文档。可是,要怎样通过我们给定的关键词快速找到这个Term呢?
当然是建索引了,为Terms建立索引,最好的就是B-Tree索引(MySQL就是B树索引最好的例子)。
我们查找Term的过程跟在MyISAM中记录ID的过程大致是一样的
MyISAM中,索引和数据是分开,通过索引可以找到记录的地址,进而可以找到这条记录
在倒排索引中,通过Term索引可以找到Term在Term Dictionary中的位置,进而找到Posting List,有了倒排列表就可以根据ID找到文档了
(PS:可以这样理解,类比MyISAM的话,Term Index相当于索引文件,Term Dictionary相当于数据文件)
(PS:其实,前面我们分了三步,我们可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以这样理解倒排索引:通过单词找到对应的倒排列表,根据倒排列表中的倒排项进而可以找到文档记录)
为了更进一步理解,用两张图来具现化这一过程:
(至于里面涉及的更加高深的数据压缩技巧,以及多个field联合查询利用跳表的数据结构快速做运算来查询,这些大家有兴趣可以自己去了解)
-
docker安装es和kibana教程
2020-08-16 19:38:16docker安装es和kibana教程 文章目录docker安装es和kibana教程1、前提2、拉去es和kibana的镜像(由于工作原因,本人拉去6.5.0版本)3、启动es4、查看启动进程5、启动kibana 1、前提 已经安装好docker 如果没有安装...docker安装es和kibana教程
1、前提
- 已经安装好docker
- 如果没有安装docker,可查看linux安装docker
2、拉去es和kibana的镜像(由于工作原因,本人拉去6.5.0版本)
-
#拉取es镜像 docker pull elasticsearch:6.5.0 #拉取kibana镜像 docker pull kibana:6.5.0
-
查看是否拉去成功
shdocker images[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Spttrgv-1597577815650)
3、启动es
#-d 代表后台启动 --name 为自定义container名字 imageId为image的ID
docker run -d --name imageId
docker run -d --name kibana:6.5.0
#本人启动命令
#创建时,调整内存的分配“ES_JAVA_OPTS=-Xms512m -Xmx512m”。
#增加9200/9300的端口映射
docker run -d --name es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e “discovery.type=single-node” elasticsearch:6.5.0[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqdbwqS8-1597577815652)(/Users/liulei/Library/Application Support/typora-user-images/image-20200816174830741.png)] * 启动报错,如上图 * ~~~sh vi /etc/sysctl.conf 添加 一行 vm.max_map_count=655360 加载参数 sysctl -p
- 重新启动es即可成功
4、查看启动进程
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXgbR093-1597577815652)(/Users/liulei/Library/Application Support/typora-user-images/image-20200816175054015.png)]
5、启动kibana
-
docker run -d --name kibana --link es:elasticsearch -p 5601:5601 kibana:6.5.0
结束
-
ES7-ES11新特性汇总
2020-07-15 09:32:57ES全称ECMAScript,ECMAScript 和 JavaScript 的关系是,前者是后者的规范,后者是前者的一种实现,从15年es6发版后,到目前的es11,es的新特性被广泛使用,成为项目开发必不可少的工具,这段时间又系统的学习了这...前言
ES全称ECMAScript,ECMAScript 和 JavaScript 的关系是,前者是后者的规范,后者是前者的一种实现,从15年es6发版后,到目前的es11,es的新特性被广泛使用,成为项目开发必不可少的工具,这段时间又系统的学习了这部分的相关知识,对其归纳总结,作为这段时间学习成果的检验。
ES7-ES11新特性汇总
-
ES7新特性归纳
-
Array.prototype.includes()
-
我们如何判断一个数组是否包含一个元素?
熟悉es5的小伙伴会首先想到indexOf(),这个方法会返回当前数组元素的下标:
const arr = ["es6", "es7", "es8", "es9", "es10", "es11"] console.log(arr.indexOf("es6")) // 0 console.log(arr.indexOf("es12")) // -1
亦或者:
const item = arr.find((item) => { return item === "es6" }) console.log(item) // "es6"
那么这两种方式有什么弊端呢,我们往下看:
const arr = ["es6", "es7", "es8", "es9", "es10", "es11", NaN] console.log(arr.indexOf(NaN)) // -1 const item = arr.find((item) => { return item === NaN }) console.log(item) // undefined
由此可以看出,es5的传统方法不满足我们的需求,无法判断数组中是否含有NaN,由此,es7提供给数组一个新的API,就是我们所说的Array.prototype.includes。
-
基本用法
const arr = ["es6", "es7", "es8", "es9", "es10", "es11",NaN] console.log(arr.includes("es6")) // true console.log(arr.includes(NaN)) // true console.log(arr.includes("es12")) // false
- Array.prototype.includes():可以接收两个参数,要搜索的值和搜索的开始索引。第二个参数可选,若为负数表示从末尾开始计数下标。
- 只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些是无法判断的。
-
includes的用法和indexOf用法相似,都可以用来判断数组中是否包含一个元素,唯一的区别在于includes可以识别NaN。
-
-
幂运算符
-
我们如何求一个数的幂运算呢?
在es5中我们可以通过以下两种方式来实现:
// 通过Math.pow() console.log(Math.pow(2,53)) // 自定义pow函数 function pow(base, exponent) { let sum = 1; for (let i = 0; i <exponent; i += 1) { sum *= base } return sum } console.log(pow(2, 53));
-
es7提供了一种 ** 运算符,可以更简单实现
console.log(2**53)
- 幂运算符的两个*号之间不能出现空格,前后有无空格都可以。
- 注意最大安全数:Number.MAX_SAFE_INTEGER = (2**53)-1
-
-
-
ES8新特性
-
async/await
- async/await是继es6中promise、generator后又一种更加优雅的异步编程的解决方案
- async函数是generator函数的语法糖
-
基本用法
// 不使用async/await function getPromise() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(1); resolve(2); }, 1000); }); } function foo() { const res = getPromise(); console.log(res); console.log(3); } foo(); // Promise {<pending>} // 3 // 1 // 使用async/await async function foo() { const res = await getPromise(); console.log(res); console.log(3); } foo(); // 1 // 2 // 3
由上面两个例子的对比就能发现,async/await可以使异步任务处理起来像是同步任务,这是因为await关键字在执行的时候会停下来,等待异步任务执行完毕(await后面一般跟的是异步任务,否则没有意义)在继续执行同步任务。
-
更优雅的异步编程的解决方案
在es6之前我们对于这个过程应该不陌生
ajax('xxx/a', res => { console.log(res) ajax('xxx/b', res => { console.log(res) ajax('xxx/c', res => { console.log(res) }) }) })
这种回调之后再回调的调用方式我们称之为“回调地狱”,这种回调方式在日常开发和项目维护当中很让人头疼。我们对比下es6中Promise的处理和es8中的async/await的处理方式就知道了为什么我们称async/await为更优雅的异步编程的解决方案。
// 以下都是模拟接口请求的代码 // Promise function getPromise(url) { return new Promise((resolve, reject) => { ajax(url, res => { resolve(res) }, err => { reject(err) }) }) } getPromise('xxx/a') .then(res => { console.log(res) return getPromise('xxx/b') }).then(res => { console.log(res) return getPromise('xxx/c') }).then(res => { console.log(res) }).catch(err => { console.log(err) }) // async/await function request(url) { return new Promise(resolve => { ajax(url, res => { resolve(res) }) }) } async function getData() { let res1 = await request('xxx/a') console.log(res1) let res2 = await request('xxx/b') console.log(res2) let res3 = await request('xxx/c') console.log(res3) } getData()
从两者的对比可以看出,Promise虽然将回调嵌套回调的方式改成平级调用,但是这种调用方式相比于async/await还是显得繁琐,而且async/await不存在回调。
-
Object.values()/Object.entries()
-
我们如何获取一个对象的每一个属性值?
在es5中我们常用Object,keys()及for in来直接获取
// Object,keys() const obj = { name: "张三", age: 18, sex: "male", } const values = Object.keys(obj).map(item => { return obj[item] }) console.log(values) // ["张三", 18, "male"] // for in for (let key in obj) { console.log(obj[key]) } // "张三", 18, "male"
es8为我们扩展了两个新的静态方法
-
Object.values()
Object.values() 返回一个数组,其元素是在对象上找到的可枚举属性值。
const obj = { name: "张三", age: 18, sex: "male", } console.log(Object.values(obj)) // ["张三", 18, "male"]
-
Object.entries
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组。
const obj = { name: "张三", age: 18, sex: "male", } console.log(Object.entries(obj)) // [["name", "张三"],["age", "18"], ["sex", "male"]]
-
for in 与Object.keys()/Object.values()/Object.entries()区别
从前面的例子可以看出for in与Object.keys()/Object.values()/Object.entries()均可以遍历对象的可枚举属性,那他们直接有什么区别呢
const obj = { name: "张三", age: 18, sex: "male", } Object.prototype.test = "test" for (let key in obj) { console.log(obj[key]) } // "张三", 18, "male","test" console.log(Object.keys(obj).map(key => obj[key])) // ["张三", 18, "male"] console.log(Object.values(obj)) // ["张三", 18, "male"] console.log(Object.entries(obj).map(([key, value]) => value)) // ["张三", 18, "male"]
for in可以遍历出原型链上的可枚举属性,而Object.keys()/Object.values()/Object.entries()只能遍历自身的可枚举属性
-
如何实现一个Object.values()/Object.entries()
const obj = { name: "张三", age: 18, sex: "male", } // Object.values function values(obj) { return Object.keys(obj).map(key => obj[key]) } // Object.entries function entries(obj) { return Object.keys(obj).map(key => [key, obj[key]]) } console.log(values(obj)) console.log(entries(obj))
-
-
Object.getOwnPropertyDescriptors()
-
前面提到可枚举属性,我们怎么设置属性的值可枚举呢?
Object.defineProperty()可以通过对描述符的设置进行更精准的控制对象属性,所谓描述符:
- value [属性的值]
- writable [属性的值是否可被改变]
- enumerable [属性的值是否可被枚举]
- configurable [描述符本身是否可被修改,属性是否可被删除]
var test = { name: '测试', value: 5 } Object.defineProperty(test, "name", { enumerable: false }) for (let key in test) { console.log(key) } // value
-
Object.getOwnPropertyDescriptors ()
Object.getOwnPropertyDescriptors ()可以返回对象属性的描述符
let test = { name: '测试', value: 5 } console.log(Object.getOwnPropertyDescriptors(test)) // { // name: {value: "测试", writable: true, enumerable: true, configurable: true} // value: {value: 5, writable: true, enumerable: true, configurable: true} // }
Object.getOwnPropertyDescriptors(target,param)接收两个参数,返回某一个参数的描述符,通过这个方法可以实现一个Object.getOwnPropertyDescriptors ()
-
Object.getOwnPropertyDescriptors()实现
let test = { name: '测试', value: 5 } function getOwnPropertyDescriptors(obj) { const result = {}; for (let key of Reflect.ownKeys(obj)) { result[key] = Object.getOwnPropertyDescriptor(obj, key); } return result; } getOwnPropertyDescriptors(test)
-
-
String.prototype.padStart()/String.prototype.padEnd()
-
padStart()
先看一个例子,希望把当前日期格式化:yyyy-mm-dd的格式:
// 返回一个yyyy-mm-dd格式的日期 function getTime() { const date = new Date(); const year = date.getFullYear() const month = date.getMonth() + 1 const day = date.getDate() return `${year}-${month}-${day}` } console.log(getTime()) // 2020-7-9
es8 中 String 新增了两个实例函数 String.prototype.padStart() 和 String.prototype.padEnd(),允许将空字符串或其他字符串添加到原始字符串的开头或结尾。
function getTime() { const date = new Date(); const year = date.getFullYear() const month = (date.getMonth() + 1).toString().padStart(2, "0") const day = (date.getDate()).toString().padStart(2, "0") return `${year}-${month}-${day}` } console.log(getTime()) // 2020-07-09
-
padEnd()
在正式项目中后台返回的数据中时间一般会转为时间戳格式,处理时间戳的时候单位都是ms毫秒(13位),但有时候有可能是s秒做单位(10位),这个时候我们需要做一个13位的补全,保证单位是毫秒。
time = String(time).padEnd(13, '0')
-
-
尾逗号
此前,函数定义和调用时,都不允许最后一个参数后面出现逗号,es8 允许函数的最后一个参数有尾逗号
// es8以前 function foo(a, b, c, d) { console.log(a, b, c, d) } // es8 function foo(a, b, c, d,) { console.log(a, b, c, d) }
-
-
ES9新特性
-
for await of/Symbol.asyncIterator
es6中有一个新特性Iteartor,只要元素符合两个协议:
- 可迭代协议:对象包含Symbol.iterator属性;
- 迭代器协议:Symbol.iterator属性必须返回一个对象,这个对象包含一个next方法,且next方法也返回一个对象,此对象包含value,done两个属性
我们就可以使用for…of去遍历这个元素。
-
我们知道 for…of 可以遍历同步运行的任务,那如果是异步任务呢,如下:
function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(time) }, time) }) } const asyncArr = [getPromise(1000), getPromise(200), getPromise(3000)] for (let item of asyncArr) { console.log(item, item.then(res => { console.log(res) })) } // Promise {<pending>} // Promise {<pending>} // Promise {<pending>} // 200 // 1000 // 3000
在上述遍历的过程中可以看到三个任务是同步启动的,我们期望的是一个异步任务执行完,在执行下一个异步任务,然而从输出可以看出不是按任务的执行顺序输出的,这显然不太符合我们的要求,在 es9 中也可以用 for…await…of 来操作:
function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ value: time, done: false, }); }, time); }); } const asyncArr = [getPromise(1000), getPromise(200), getPromise(3000)]; asyncArr[Symbol.asyncIterator] = function () { let nextIndex = 0; return { next() { return nextIndex < asyncArr.length ? asyncArr[nextIndex++] : Promise.resolve({ value: undefined, done: true, }); }, }; }; async function test() { for await (let item of asyncArr) { console.log(Date.now(), item); } } test(); // 1594374685156 1000 // 1594374685157 200 // 1594374687157 3000
await需要在async 函数或者 async 生成器里面使用
-
同步迭代器/异步迭代器
类别 同步迭代器 异步迭代器 迭代器协议 Symbol.iterator Symbol.asyncIteartor 遍历 for…of for…await…of
-
正则的扩展
-
dotAll/s
一句话总结dotAll模式就是:在正则中使用(.)字符时使用s修饰符可以解决(.)字符不能匹配行终止符的例外
console.log(/./.test(1)); console.log(/./.test("1")); console.log(/./.test("\n")); console.log(/./.test("\r")); console.log(/./.test("\u{2028}")); // true // true // false // false // false // 使用s修饰符 console.log(/./s.test(1)); console.log(/./s.test("1")); console.log(/./s.test("\n")); console.log(/./s.test("\r")); console.log(/./s.test("\u{2028}")); // true // true // true // true // true
- (.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符
- 正则中可以使用的修饰符有i,g,m,y,u,s
-
具名组匹配
我们先看一个例子
console.log("2020-07-10".match(/(\d{4})-(\d{2})-(\d{2})/)); // ["2020-07-10", "2020", "07", "10", index: 0, input: "2020-07-10", groups: undefined]
按照 match 的语法,没有使用 g 修饰符,所以返回值第一个数值是正则表达式的完整匹配,接下来的第二个值到第四个值是分组匹配(2020, 07, 10),我们想要获取年月日的时候不得不通过数组的下标去获取,这样显得不灵活。仔细观察 match 返回值还有几个属性,分别是 index、input、groups。
- index [匹配的结果的开始位置]
- input [匹配的字符串]
- groups [捕获组 ]
所谓的具名组匹配就是命名捕获分组:
console.log("2020-07-10".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/)); // groups的值 groups: {year: "2020", month: "07", day: "10"}
这样我们就可以通过groups及命名分组获取对应的年月日的值了。
-
后行断言
let test = 'world hello' console.log(test.match(/(?<=world\s)hello/))
(?<)是后行断言的符号配合= 、!等使用。
-
-
对象的Rest和Spread语法
-
一个例子对比理解对象的Rest和Spread语法
const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; // 数组合并 const arr = [...arr1, ...arr2]; console.log(arr); const obj1 = { a: 1 }; const obj2 = { b: 2 }; // 对象合并 const obj = { ...obj1, ...obj2 }; console.log(obj); // [1, 2, 3, 4, 5, 6] // {a: 1, b: 2}
一句话总结就是(…)运算符在数组中可以怎样使用,在对象就可以怎样使用。
-
-
Promise.prototype.finally()
-
不管promise状态如何都会执行的回调函数
new Promise((resolve, reject) => { resolve(1); }) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }) .finally(() => { console.log("finally"); }); // 1 // promise
-
-
带标签的模板字符串扩展
es9 新特性中移除了对 ECMAScript带标签的模板字符串中转义序列的语法限制。 遇到不合法的字符串转义返回undefined,并且从raw上可获取原字符串
function foo(str) { console.log(str); } foo`\undfdfdf`; // es9以前报错 // es9:[undefined, raw:["\undfdfdf"]]
-
-
ES10新特性
-
Object.fromEntries()
es8中对象添加了一个entries()静态方法,这个方法返回一个给定对象自身可枚举属性的键值对数组 ,Object.fromEntries()方法与 Object.entries() 正好相对,可以将键值对列表转换为一个对象 。
const obj = { x: 1, y: 2, }; const entries = Object.entries(obj); console.log(entries); console.log(Object.fromEntries(entries)); // [["x",1],["y":2]] // {x:1,y:2}
只要符合entries结构的都可以使用Object.fromEntries(entries)将键值对列表转换为一个对象,比如Map
-
String.prototype.trimStart()/String.prototype.trimEnd()
-
trimStart() /trimLeft()
trimLeft是trimStart的别名,作用是去掉字符串左边的空格
-
trimEnd() / trimRight()
trimEnd是trimRight的别名,作用是去掉字符串右边的空格
const str = " hello world "; console.log(str.trimStart()); console.log(str.trimEnd()); console.log(str.trim()); // "hello world " // " hello world" // "hello world"
-
-
Array.prototype.flat()/Array.prototype.flatMap()
-
Array.prototype.flat()
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回 。
const arr = [1, [2, [3, [4, [5, [6, 7], 8], 9]]]]; console.log(arr.flat(1)); console.log(arr.flat(5)); console.log(arr.flat(Infinity)); // [1,2,[3, [4, [5, [6, 7], 8], 9]]] // [1,2,3,4,5,6,7,8,9] // [1,2,3,4,5,6,7,8,9]
-
自定义实现flat
function flat(arr, deep = 1) { const newArray = []; let deepNum = 0; const flatMap = (arr) => { arr.map((item, index, array) => { if (Array.isArray(item)) { if (deepNum < deep) { deepNum++; flatMap(item); } else { newArray.push(item); } } else { newArray.push(item); if (index === array.length - 1) deepNum = 0; } }); }; flatMap(arr); return newArray; } const arr = [1, [2, [3, [4, [5, 6], 7], 8]]]; console.log(flat(arr, 4));
-
Array.prototype.flatMap()
flatMap实质上包含两部分功能,一是map,二是flat
const numbers = [1, 2, 3]; console.log(numbers.map((x) => [x ** 2]).flat()); console.log(numbers.flatMap((x) => [x ** 2])); // [1,4,9] // [1,4,9]
-
-
Symbol.description
-
可以通过 description 获取 Symbol 的描述
const symbol = Symbol("symbol"); console.log(symbol.description); // symbol console.log(symbol.description === "symbol"); // true
在es10以前,我们只能通过调用 Symbol 的 toString() 时才可以读取这个属性
console.log(symbol.toString() === "Symbol(symbol)");
-
-
Function.prototype.toString()
-
Function.prototype.toString() 方法返回一个表示当前函数源代码的字符串
function test(a) { // es10以前不返回注释部分 console.log(a); } console.log(test.toString()); // function test(a) { // // es10以前不返回注释部分 // console.log(a); // }
-
-
catch Building
-
es10允许我们在捕获异常时省略catch的参数
// es10以前 try { throw new Error(); } catch (error) { console.log("fail"); } // es10 try { throw new Error(); } catch { console.log("fail"); }
-
-
JSON扩展
-
JSON 内容可以支持包含 U+2028行分隔符 与 U+2029段分隔符
-
在 ES10 JSON.stringify 会用转义字符的方式来处理 超出范围的 Unicode 展示错误的问题 而非编码的方式
console.log(JSON.stringify('\uD83D\uDE0E')) // 笑脸 // 单独的\uD83D其实是个无效的字符串 // 之前的版本 ,这些字符将替换为特殊字符,而现在将未配对的代理代码点表示为JSON转义序列 console.log(JSON.stringify('\uD83D')) // "\ud83d"
-
-
-
ES11新特性
-
BigInt
es11为我们提供了第七种新的原始数据类型,对于js来说,他的最大取值范围是2的53次方
console.log(2 ** 53); console.log(2 ** 53 + 1); console.log(Number.MAX_SAFE_INTEGER); // 9007199254740992 // 9007199254740992 // 9007199254740991
BigInt,表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方 。
-
使用方式
// 方式一 console.log(9007199254740993); console.log(9007199254740993n); // 9007199254740992 // 9007199254740993n // 方式二 console.log(9007199254740993); console.log(BigInt(9007199254740993n)); // 9007199254740992 // 9007199254740993n
- 1==1n // true
- 1 === 1n // false
- typeof 1n // bigint
- BigInt(9007199254740993n).toString() // 9007199254740993
-
-
可选链
可选链可以使我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验。
const a = { b: { c: { d: { e: "111", }, }, }, }; // es11前 const value = a && a.b && a.b.c && a.b.c.d && a.b.c.d.e; console.log(value); // es11:可选链 const value2 = a?.b?.c?.d?.e; console.log(value2);
可选链中的 ? 表示如果问号左边表达式有值, 就会继续查询问号后面的字段 , 可以大量简化类似繁琐的前置校验操作 。
-
空值合并运算符
当我们查询某个属性时,经常会遇到,如果没有该属性就会设置一个默认的值。
const a = 0; const b = a || 1; console.log(b); // 1
我们在使用||运算符时, 变量值为 0 就是 false ,所以我们会看到上述结果会输出1,但是很多时候我们希望b的输出结果就是a的值0,es11提出了空值合并运算符(??),当左侧操作数为 null 或 undefined 时,其返回右侧的操作数。否则返回左侧的操作数。
const a = 0; const b = a ?? 1; console.log(b); // 0
-
Promise.allSettled()
es6中 Promise.all方法接受一个数组元素都是由 Promise.resolve 包装的数组, 生成并返回一个新的 Promise 对象, 如果参数中的任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的 Promise 对象。
// 全部返回resolve function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(time); }, time); }); } Promise.all([getPromise(1000), getPromise(2000), getPromise(3000)]).then( (res) => { console.log(res); } ); // [1000,2000,3000] // 返回reject function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(time); }, time); }); } function getReject(time) { return new Promise((resolve, reject) => { setTimeout(() => { reject(time); }, time); }); } Promise.all([getPromise(1000), getReject(2000), getPromise(3000)]) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); // 2000
从上面可以看出Promise.all只要有一个任务返回reject,整个任务都会失败, 我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态 ,这就是Promise.allSettled()的作用。
function getPromise(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(time); }, time); }); } function getReject(time) { return new Promise((resolve, reject) => { setTimeout(() => { reject(time); }, time); }); } Promise.allSettled([getPromise(1000), getReject(2000), getPromise(3000)]) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); // [{status: "fulfilled", value: 1000}, // {status: "rejected", reason: 2000}, // {status: // "fulfilled", value: 3000}]
-
import
-
按需加载
现代前端打包资源越来越大,打包成几M的JS资源已成常态,而往往前端应用初始化时根本不需要全量加载逻辑资源,为了首屏渲染速度更快,很多时候都是按需加载,比如懒加载图片等。
(async () => { if (somethingIsTrue) { // import module for side effects await import('xxx/xxx.js'); } })();
-
-
String.prototype.matchAll()
- matchAll() 方法返回一个包含所有匹配正则表达式及分组捕获结果的迭代器 ;
- 使用: str.matchAll(regexp) ;
字符串处理的一个常见场景是想要匹配出字符串中的所有目标子串,例如:
-
match()
const str = "es2015/es6 es2016/es7 es2017/es8 es2018/es9 es2019/es10 es2020/es10"; console.log(str.match(/(es\d+)\/es(\d+)/g)); // ["es2015/es6", "es2016/es7", "es2017/es8", "es2018/es9", "es2019/es10", //"es2020/es10"]
match()方法中,正则表达式所匹配到的多个结果会被打包成数组返回,但无法得知每个匹配除结果之外的相关信息,比如捕获到的子串,匹配到的
index
位置等 。 -
exec ()
const str = "es2015/es6 es2016/es7 es2017/es8 es2018/es9 es2019/es10 es2020/es10"; const reg = /(es\d+)\/es(\d+)/g; let matched; let formatted = []; while ((matched = reg.exec(str))) { formatted.push(`${matched[1]}-es${matched[2]}`); } console.log(formatted); //["es2015-es6","es2016-es7","es2017-es8","es2018-es9","es2019-es10", //"es2020-es10"]
-
matchAll()
const str = "es2015/es6 es2016/es7 es2017/es8 es2018/es9 es2019/es10 es2020/es10"; const reg = /(es\d+)\/es(\d+)/g; const matchs = []; for (let match of str.matchAll(reg)) { matchs.push(`${match[1]}-es${match[2]}`); } console.log(matchs); // ["es2015-es6", "es2016-es7", "es2017-es8", "es2018-es9", "es2019-es10", "es2020-es10"]
matchAll() 是返回一个迭代器,对大数据量的场景更友好 。
-
globalThis
Javascript 在不同的环境获取全局对象有不通的方式:
- node 中通过 global,
- web 中通过 window, self 。
es11提出的globalThis一句话总结就是: 无论是在node环境还是web中,全局作用域中的 this 可以通过globalThis访问, 不必担心它的运行环境 。
-
for…in遍历机制
JavaScript 中通过for-in遍历对象时 key 的顺序是不确定的,因为规范没有明确定义,并且能够遍历原型属性让for-in的实现机制变得相当复杂,不同 JavaScript 引擎有各自根深蒂固的不同实现,很难统一
- 所以 es11不要求统一属性遍历顺序,而是对遍历过程中的一些特殊 Case 明确定义了一些规则:
- 遍历不到 Symbol 类型的属性
- 遍历过程中,目标对象的属性能被删除,忽略掉尚未遍历到却已经被删掉的属性
- 遍历过程中,如果有新增属性,不保证新的属性能被当次遍历处理到
- 属性名不会重复出现(一个属性名最多出现一次)
- 目标对象整条原型链上的属性都能遍历到
-
相关文档:
-
-
FFmpeg+OpenGL ES+OpenSL ES打造Android视频播放器
2018-05-06 13:53:54FFmpeg+OpenGL ES+OpenSL ES打造Android视频播放器教程,该课程基于C++语言,用FFmpeg、OpenGL ES、OpenSL ES和MediaCodec打造Android视频播放器。以录播课形式讲解课程所涉及的知识点和整体流程,每节课都有相关的... -
es head连接 es教程
2020-03-08 18:27:311.下载es-header 链接: link. 1)安装grunt grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作,5.0里的head插件就是通过grunt启动的。因此需要安装一下grunt: 1.进入elasticsearch-head安装...环境:
linux centos
java 8 java -version
node.js node -v1.下载es-header
链接: link.
1)安装grunt
grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作,5.0里的head插件就是通过grunt启动的。因此需要安装一下grunt:
1.进入elasticsearch-head安装目录npm install -g grunt-cli //执行后会生成node_modules文件夹 npm install
2)修改head源码
1、修改hostname属性
2、修改连接地址
目录:vi /home/ntc/code/elasticsearch-head/_site/app.js 修改head的连接地址: this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://localhost:9200"; 把localhost修改成你es的服务器地址,如: this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://192.168.40.133:9200";
3、启动
grunt server &
3)配置es
http.cors.enabled: true http.cors.allow-origin: "*"
-
es 问题
2018-03-02 18:26:321,elasticsearch can not run as rootgroupadd es useradd es -g es runuser es ./elasticserch2, 修改配置后运行,es file descriptors [4096]等等,需要修改系统限制ERROR: bootstrap checks failed max file ... -
es复合条件查询
2019-07-14 13:26:26在es中,使用组合条件查询是其作为搜索引擎检索数据的一个强大之处,在前几篇中,简单演示了es的查询语法,但基本的增删改查功能并不能很好的满足复杂的查询场景,比如说我们期望像mysql那样做到拼接复杂的条件进行... -
(ElasticSearch)es 权威指南 、 es参考手册API 、es 中文社区
2018-06-30 20:20:21es权威指南 (电脑左侧栏为章节目录) es参考手册API -
OpenGL ES2.0基础
2015-05-27 16:39:31初级学习OpenGL ES2.0的课程,从无到有,从进本的函数讲起,每一课时都附带一个例子程序。深入浅出的讲解可编程管线技术,令人费解的文理,以及混合技术,各种优化技术:顶点缓冲区,索引缓冲区,帧缓冲区,介绍精灵... -
ES(四)ES使用(基本查询、聚合查询)
2019-01-08 22:31:50基本操作 操作索引 1.新建索引 curl -XPUT localhost:9200/index01 2.查看索引 curl -XGET http://192.168.168.101:9200/index01/_settings curl -XGET ...3.删除索引 curl -XDELETE ht... -
springboot+es
2019-04-14 14:42:34springboot-es 本文 :Elasticsearch 与 sprigboot 的结合,springboot 操作es 关于es 的介绍和初识 可以看 https://blog.csdn.net/u012373815/article/details/50460248 安装 ...... -
OpenGL ES 3.0 对比 OpenGL ES 2.0 的异同点和新功能
2019-03-28 00:55:32相比于 OpenGL ES 1.x 系列的固定功能管线,OpenGL ES 2.0 和 OpenGL ES 3.0 都是可编程图形管线。开发者可以自己编写图形管线中的 顶点着色器 和 片段着色器 两个阶段的代码。 二、不同点 OpenGL ES 3.0 是向后... -
【OpenGL ES】OpenGL ES简介
2017-04-25 20:12:48【参考-khronos】https://www.khronos.org/opengles/1、简介OpenGL ES(OpenGL for Embeded System)是OpenGL(Open Graphics Library)的精简子集,是以手持和嵌入式设备为目标的高级3D图形API,如现在火爆的智能... -
【es】es 批量upsert
2019-02-16 11:14:22es 批量upsert 使用场景 批量操作数据 如果存在这条数据,则更新,如果不存在这条数据 则插入 代码实现 private void insert(List<SaleStorageIn> saleStorageIns) { ... -
ES系列之原来ES的聚合统计不准确啊
2020-03-15 21:41:20本篇文章不是讲ElasticSearch(下面简称ES)聚合分析的基本概念和用法的,这些网上的资料很多,不清楚的可以自行查阅。 我下面聚合分析使用的数据都是kibana自带的,这样方便有些读者实际测试文中的示例。 基本概念 ... -
ES:ES支持的数据类型
2020-05-31 17:43:43ES支持的数据类型: 核心类型 字符串类型 : string: text: keyword: 整数类型: long integer short byte 浮点类型 double, float, half_float, scaled_float 逻辑类型 :boolean 日期类型 :... -
ES(二)ES安装及集群的搭建
2019-01-07 22:01:10ES安装 安装步骤 准备安装包https://www.elastic.co/downloads/elasticsearch 解压安装包tar -xvf elasticsearch-5.5.2.tar.gz 安装完成 创建一个es用户(es不能使用root运行) groupadd es useradd es -g es -p es ... -
深入了解ES之ES集群的启动流程
2020-03-13 20:20:49ES集群的启动流程 ES的在启动的过程中主要会经过: 1.electmaster(选举主节点) ES的选主算法是基于Bully算法的改进,主要的思路是对节点ID的排序,取ID值最大的节点,作为Master,每个节点都运行这个流程。 参赛人数... -
ES插件es-head下载和安装
2019-06-18 17:02:13ES插件es-head下载和安装 下载elasticsearch-head并解压 在线下载:wget https://github.com/mobz/elasticsearch-head/archive/master.zip 或者到github下载:https://github.com/mobz/elasticsearch-head unzip... -
Java操作ES(三):RestHighLevelClient查询ES
2020-04-01 21:33:30RestHighLevelClient查询ES中数据的API主要有:get、multiGet、search、multiSearch、searchScroll,每个方法还有异步查询的操作方法。下面我们就逐个看看这些API的应用。 链接ES构建客户端: public class ... -
ES学习——ES评分简单介绍
2019-03-30 19:00:30当我们能使用match来搜索匹配数据的时候,es会给每一个文档进行评分(匹配度),并根据评分的大小对结果文档进行排序。 介绍 es的实时评分机制是基于 Lucene 的基础上实现的,最常见的是 TF/IDF和BM25这两种评分模型... -
ES插件es-head安装
2018-03-17 23:08:29安装Head 插件Elasticsearch Head Plugin: 对ES进行各种操作,如查询、删除、浏览索引等。1、下载elasticsearch-head并解压在线下载:wget https://github.com/mobz/elasticsearch-head/archive/master.zip或者到... -
docker安装ES及ik插件和ES常用查询语句
2020-02-24 17:53:19es docker 安装 安装过程如下: 首先在docker hub 拉取elk 镜像 (因为我用的是630 版本所以加了版本号)https://hub.docker.com/r/sebp/elk 关于容器更多信息查看 https://elk-docker.readthedocs.io/ docker pull ... -
ES5, ES2015 和 TypeScript 的区别
2017-09-04 20:00:53转自:...ES5, ES2015 和 TypeScript 的区别 【已翻译100%】 英文原文:Understanding ES5, ES2015 and TypeScript 标签: TypeScript thinkgood 推荐于 1年前 (共 10 段 -
es安全认证配置
2020-08-13 18:08:071.在es的配置yml文件中增加下面配置 xpack.security.enabled: true xpack.license.self_generated.type: basic xpack.security.transport.ssl.enabled: true 2.重启es服务 3.建立用户密码 ./bin/elasticsearch-setup... -
OpenGL ES
2016-04-28 14:57:17原文地址:... OpenGl 支持 2D和3D图形开源库。 ...Android支持多个版本的OpenGL ES API: ...OpenGL ES 1.0和1.1 -这个API规范支持Android 1.0和更高版本。OpenGL ES 2.0 -
ES(一)ES基本概念
2019-01-07 21:08:05ES简介 ES是基于Lucene分布式搜索服务,可以存储整个对象或文档 分布式的实时文件存储,每个字段都被索引并可被搜索 分布式的实时分析搜索引擎 可以扩展到上百台服务器,处理PB级结构化或非结构化数据 与传统数据库... -
ELasticSearch-ES集群原理与搭建
2020-08-11 10:55:56ES集群原理 查看集群健康状况:URL+ /GET _cat/health (1)、首先弄清ES基本概念名词 Cluster 代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是...
-
JavaWeb过滤器
-
Navicat for MySQL_11.2.15.zip
-
Selenium3分布式与虚拟化
-
hadoop自动化运维工具Ambari应用实践
-
靶向测序基因型检测(GBTS)技术及其应用.pdf
-
OPENCV官方出品开源图片标注工具CVAT在Ubuntu18.04上部署
-
java集合类面试题
-
macOS下mysql5.7安装包
-
python办公自动化技巧
-
阿里云云计算ACP考试必备教程
-
转行做IT-第2章 HTML入门及高级应用
-
【数据分析-随到随学】Mysql数据库
-
习题10-5 递归计算Ackermenn函数 (15分)
-
macOS-python3.7安装包.zip
-
postgresql模糊查询不区分大小写
-
中南大学《GPS数据处理》考试试卷题.pdf
-
电商设计专业思维
-
分享关于redis分布式锁的续锁方案
-
C语言实验报告七.pdf
-
微服务系列第七十一季-Spring入门