首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Docker技术入门与实战(第2版)2.2 安装Docker

2.2 安装Docker Docker在主流的操作系统和云平台上都可以使用,包括Linux操作系统(如Ubuntu、Debian、CentOS、Redhat等)、MacOS操作系统和Windows操作系统,以及AWS等云平台。 用户可以访问Docker官网的Get Docker(https://www.docker.com/products/overview)页面,查看获取Docker的方式,以及Docker支持的平台类型,如图2-2所示。 图2-2 获取Docker 在Get Docker页面,我们可以看到目前Docker支持Docker Platform、Docker Hub、Docker Cloud和Docker DataCenter。 Docker Platform:支持在桌面系统或云平台安装Docker; DockerHub:官方

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.8 本章小结

3.8 本章小结 本章具体介绍了围绕Docker镜像的一系列重要命令操作,包括获取、查看、搜索、删除、创建、存出和载入、上传等。 镜像是使用Docker的前提,也是最基本的资源。所以,在平时的Docker使用中,要注意积累自己定制的镜像文件,并将自己创建的高质量镜像分享到社区中。 在后续章节,笔者将介绍更多对镜像进行操作的场景。

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.1 获取镜像

使用Docker镜像 镜像(image)是Docker三大核心概念中最为重要的,自Docker诞生之日起“镜像”就是相关社区最为热门的关键词。 Docker运行容器前需要本地存在对应的镜像,如果镜像没保存在本地,Docker会尝试先从默认镜像仓库下载(默认使用Docker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。 本章将介绍围绕镜像这一核心概念的具体操作,包括如何使用pull命令从Docker Hub仓库中下载镜像到本地,如何查看本地已有的镜像信息和管理镜像标签,如何在远端仓库使用search命令进行搜索和过滤,如何删除镜像标签和镜像文件,如何创建用户定制的镜像并且保存为外部文件。最后,还介绍如何往Docker Hub仓库中推送自己的镜像。 一份非官方研究报告表明,image一直是Docker官方社区(2

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)2.5 本章小结

2.5 本章小结 本章介绍了Docker的三大核心概念:镜像、容器和仓库。在后面的实践中,读者会感受到,基于三大核心概念所构建的高效工作流程,正是Docker从众多容器虚拟化方案中脱颖而出的重要原因。实际上,Docker的工作流也并非凭空创造的,很大程度上参考了Git和Github的设计理念,从而为应用分发和团队合作都带来了众多优势。 在后续章节,笔者将具体讲解围绕这三大核心概念的Docker操作命令。

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.4 删除镜像

3.4 删除镜像 1.?使用标签删除镜像 使用docker rmi命令可以删除镜像,命令格式为docker rmi IMAGE [IMAGE...],其中IMAGE可以为标签或ID。 例如,要删除掉myubuntu:latest镜像,可以使用如下命令: $ docker rmi myubuntu:latest Untagged: myubuntu:latest 读者可能会担心,本地的ubuntu:latest镜像是否会受此命令的影响。无需担心,当同一个镜像拥有多个标签的时候,docker rmi命令只是删除该镜像多个标签中的指定标签而已,并不影响镜像文件。因此上述操作相当于只是删除了镜像2fa927b5cdd3的一个标签而已。 为保险起见,再次查看本地的镜像,发现ubuntu:latest镜像(准确地说是2fa927b5cdd3镜像)仍然存在:

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.5 创建镜像

3.5 创建镜像 创建镜像的方法主要有三种:基于已有镜像的容器创建、基于本地模板导入、基于Dockerf?ile创建。 本节将重点介绍前两种方法。最后一种基于Dockerfile创建的方法将在后续章节专门予以详细介绍。 1.?基于已有镜像的容器创建 该方法主要是使用docker commit命令。命令格式为docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]],主要选项包括: -a, --author="":作者信息; -c, --change=[]:提交的时候执行Dockerf?ile指令,包括CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR等; -m, --message="":提交消息; -p, --pause=true:

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.3 搜寻镜像

3.3 搜寻镜像 使用docker search命令可以搜索远端仓库中共享的镜像,默认搜索官方仓库中的镜像。用法为docker search TERM,支持的参数主要包括: --automated=true|false:仅显示自动创建的镜像,默认为否; --no-trunc=true|false:输出信息不截断显示,默认为否; -s, --stars=X:指定仅显示评价为指定星级以上的镜像,默认为0,即输出所有镜像。 例如,搜索所有自动创建的评价为1+的带nginx关键字的镜像,如下所示: $ docker search --automated -s 3 nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED jwilder/nginx

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)3.7 上传镜像

3.7 上传镜像 可以使用docker push命令上传镜像到仓库,默认上传到Docker Hub官方仓库(需要登录)。命令格式为: docker push NAME[:TAG] | [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG] 用户在Docker Hub网站注册后可以上传自制的镜像。例如用户user上传本地的test:latest镜像,可以先添加新的标签user/test:latest,然后用docker push命令上传镜像: $ docker tag test:latest user/test:latest $ docker push user/test:latest The push refers to a repository [docker.io/user/test] Sending imag

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)2.1 核心概念

核心概念与安装配置 本章首先介绍Docker的三大核心概念。 镜像(Image) 容器(Container) 仓库(Repository) 只有理解了这三个核心概念,才能顺利地理解Docker容器的整个生命周期。 随后,笔者将介绍如何在常见的操作系统平台上安装Docker,包括Ubuntu、CentOS、MacOS和Windows等主流操作系统平台。 2.1 核心概念 Docker的大部分操作都围绕着它的三大核心概念——镜像、容器和仓库而展开。因此,准确把握这三大核心概念对于掌握Docker技术尤为重要。 1.?Docker镜像 Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。可以把它称为一个Apache镜像。 镜像是创建Docker

优秀的个人博客,低调大师

Docker技术入门与实战(第2版)1.4 本章小结

1.4 本章小结 本章介绍了容器虚拟化的基本概念、Docker的诞生及发展历史,以及容器在云时代应用分发场景下的巨大优势。 与传统的虚拟机相比,容器虚拟化方式在很多场景下都有极为明显的优势。无论是系统管理员、应用开发人员、测试人员以及运维管理人员,都应该尽快掌握Docker,尽早享受其带来的巨大便利。 后续章节,笔者将结合实践案例具体介绍Docker的安装、使用,让我们一起开启精彩的Docker之旅。

优秀的个人博客,低调大师

《读书报告 – Elasticsearch入门 》----Part II 深入搜索(2)

第十三章 全文检索 这一章开始介绍 全文检索 :怎样对全文字段(full-text fields)进行检索以找到相关度最高的文档。 全文检索最重要的两个方面是: 相关度(Relevance) 根据文档与查询的相关程度对结果集进行排序的能力。相关度可以使用TF/IDF、地理位置相近程度、模糊相似度或其他算法计算。 分析(Analysis) 将一段文本转换为一组唯一的、标准化了的标记(token),用以(a)创建倒排索引,(b)查询倒排索引。 注意,一旦提到相关度和分析,指的都是查询(queries)而非过滤器(filters)。 基于短语 vs. 全文 虽然所有的查询都会进行相关度计算,但不是所有的查询都有分析阶段。而且像bool或function_score这样的查询并不在文本字段执行。文本查询可以分为两大类: 1. 基于短语(Term-based)的查询: 像term或fuzzy一类的查询是低级查询,它们没有分析阶段。这些查询在单一的短语上执行。例如对单词'Foo'的term查询会在倒排索引里精确地查找'Foo'这个词,并对每个包含这个单词的文档计算TF/IDF相关度'_score'。 牢记term查询只在倒排查询里精确地查找特定短语,而不会匹配短语的其它变形,如foo或FOO。不管短语怎样被加入索引,都只匹配倒排索引里的准确值。如果你在一个设置了'not_analyzed'的字段为'["Foo", "Bar"]'建索引,或者在一个用'whitespace'解析器解析的字段为'Foo Bar'建索引,都会在倒排索引里加入两个索引'Foo'和'Bar'。 2. 全文(Full-text)检索 match和query_string这样的查询是高级查询,它们会对字段进行分析: 如果检索一个'date'或'integer'字段,它们会把查询语句作为日期或者整数格式数据。 如果检索一个准确值('not_analyzed')字符串字段,它们会把整个查询语句作为一个短语。 如果检索一个全文('analyzed')字段,查询会先用适当的解析器解析查询语句,产生需要查询的短语列表。然后对列表中的每个短语执行低级查询,合并查询结果,得到最终的文档相关度。 我们将会在后续章节讨论这一过程的细节。 我们很少需要直接使用基于短语的查询。通常我们会想要检索全文,而不是单独的短语,使用高级的全文检索会更简单(全文检索内部最终还是使用基于短语的查询)。 13.1 匹配查询 不管搜索什么内容,match查询是首先需要接触的查询。它是一个高级查询,意味着match查询知道如何更好的处理全文检索和准确值检索。 这也就是说,match查询的一个主要用途是进行全文搜索。通过一个小例子来看一下全文搜索是如何工作的。 索引一些数据 首先,我们使用bulk API来创建和索引一些文档: DELETE /my_index <1> PUT /my_index_second { "settings": { "number_of_shards": 1 }} <2> POST /my_index/my_type/_bulk { "index": { "_id": 1 }} { "title": "The quick brown fox" } { "index": { "_id": 2 }} { "title": "The quick brown fox jumps over the lazy dog" } { "index": { "_id": 3 }} { "title": "The quick brown fox jumps over the quick dog" } { "index": { "_id": 4 }} { "title": "Brown fox brown dog" } <1> 删除已经存在的索引(如果索引存在) <2> 然后,关联失效这一节解释了为什么我们创建该索引的时候只使用一个主分片。 单词查询 第一个例子解释了当使用match查询进行单词全文搜索时发生了什么: GET /my_index_second/my_type/_search { "query": { "match": { "title": "QUICK!" } } } Elasticsearch通过下面的步骤执行match查询: 检查field类型 title字段是一个字符串(analyzed),所以该查询字符串也需要被分析(analyzed) 分析查询字符串 查询词QUICK!经过标准分析器的分析后变成单词quick。因为我们只有一个查询词,因此match查询可以以一种低级别term查询的方式执行。 找到匹配的文档 term查询在倒排索引中搜索quick,并且返回包含该词的文档。在这个例子中,返回的文档是1,2,3。 为每个文档打分 term查询综合考虑词频(每篇文档title字段包含quick的次数)、逆文档频率(在全部文档中title字段包含quick的次数)、包含quick的字段长度(长度越短越相关)来计算每篇文档的相关性得分_score。(更多请见相关性介绍) 这个过程之后我们将得到以下结果(简化后): "hits": [ { "_id": "1", "_score": 0.5, <1> "_source": { "title": "The quick brown fox" } }, { "_id": "3", "_score": 0.44194174, <2> "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "2", "_score": 0.3125, <2> "_source": { "title": "The quick brown fox jumps over the lazy dog" } } ] <1> 文档1最相关,因为 title 最短,意味着quick在语义中起比较大的作用。 <2> 文档3比文档2更相关,因为在文档3中quick出现了两次。 多词查询 如果一次只能查询一个关键词,全文检索将会很不方便。幸运的是,用match查询进行多词查询也很简单: GET /my_index_second/my_type/_search { "query": { "match": { "title": "BROWN DOG!" } } } 上面这个查询返回以下结果集: { "hits": [ { "_id": "4", "_score": 0.73185337, <1> "_source": { "title": "Brown fox brown dog" } }, { "_id": "2", "_score": 0.47486103, <2> "_source": { "title": "The quick brown fox jumps over the lazy dog" } }, { "_id": "3", "_score": 0.47486103, <2> "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "1", "_score": 0.11914785, <3> "_source": { "title": "The quick brown fox" } } ] } <1> 文档4的相关度最高,因为包含两个”brown”和一个”dog”。 <2> 文档2和3都包含一个”brown”和一个”dog”,且’title’字段长度相同,所以相关度相等。 <3> 文档1只包含一个”brown”,不包含”dog”,所以相关度最低。 因为match查询需要查询两个关键词:"brown"和"dog",在内部会执行两个term查询并综合二者的结果得到最终的结果。match的实现方式是将两个term查询放入一个bool查询,bool查询在之前的章节已经介绍过。 重要的一点是,'title'字段包含至少一个查询关键字的文档都被认为是符合查询条件的。匹配的单词数越多,文档的相关度越高。 提高精度 匹配包含任意个数查询关键字的文档可能会得到一些看似不相关的结果,这是一种霰弹策略(shotgun approach)。然而我们可能想得到包含所有查询关键字的文档。换句话说,我们想得到的是匹配'brown AND dog'的文档,而非'brown OR dog'。 match查询接受一个'operator'参数,默认值为or。如果要求所有查询关键字都匹配,可以更改参数值为and: GET /my_index/my_type/_search { "query": { "match": { "title": { <1> "query": "BROWN DOG!", "operator": "and" } } } } <1> 为了加入'operator'参数,match查询的结构有一些不同。 这个查询会排除文档1,因为文档1只包含了一个查询关键词。 控制精度 在 all 和 any 之间的选择有点过于非黑即白。如果用户指定了5个查询关键字,而一个文档只包含了其中的4个?将'operator'设置为'and'会排除这个文档。 有时这的确是用户想要的结果。但在大多数全文检索的使用场景下,用户想得到相关的文档,排除那些不太可能相关的文档。换句话说,我们需要介于二者之间的选项。 match查询有'minimum_should_match'参数,参数值表示被视为相关的文档必须匹配的关键词个数。参数值可以设为整数,也可以设置为百分数。因为不能提前确定用户输入的查询关键词个数,使用百分数也很合理。 GET /my_index/my_type/_search { "query": { "match": { "title": { "query": "quick brown dog", "minimum_should_match": "75%" } } } } 当'minimum_should_match'被设置为百分数时,查询进行如下:在上面的例子里,'75%'会被下舍为'66.6%',也就是2个关键词。不论参数值为多少,进入结果集的文档至少应匹配一个关键词。 [提示] 'minimum_should_match'参数很灵活,根据用户输入的关键词个数,可以采用不同的匹配规则。 要全面理解match查询是怎样处理多词查询,我们需要了解怎样用bool查询合并多个查询。 13.2 组合查询 在《组合过滤》中我们讨论了怎样用布尔过滤器组合多个用and, or, and not逻辑组成的过滤子句,在查询中, 布尔查询充当着相似的作用,但是有一个重要的区别。 过滤器会做一个判断: 是否应该将文档添加到结果集? 然而查询会做更精细的判断. 他们不仅决定一个文档是否要添加到结果集,而且还要计算文档的相关性(relevant). 像过滤器一样, 布尔查询接受多个用must, must_not, and should的查询子句. 例: GET /my_index/my_type/_search { "query": { "bool": { "must": { "match": { "title": "quick" }}, "must_not": { "match": { "title": "lazy" }}, "should": [ { "match": { "title": "brown" }}, { "match": { "title": "dog" }} ] } } } 在前面的查询中,凡是满足title字段中包含quick,但是不包含lazy的文档都会在查询结果中。到目前为止,布尔查询的作用非常类似于布尔过滤的作用。 当should过滤器中有两个子句时不同的地方就体现出来了,下面例子就可以体现:一个文档不需要同时包含brown和dog,但如果同时有这两个词,这个文档的相关性就更高: { "hits": [ { "_id": "3", "_score": 0.70134366, <1> "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "1", "_score": 0.3312608, "_source": { "title": "The quick brown fox" } } ] } <1> 文档3的得分更高,是因为它同时包含了brown 和 dog。 得分计算 布尔查询通过把所有符合must 和 should的子句得分加起来,然后除以must 和 should子句的总数为每个文档计算相关性得分。 must_not子句并不影响得分;他们存在的意义是排除已经被包含的文档。 精度控制 所有的 must 子句必须匹配, 并且所有的 must_not 子句必须不匹配, 但是多少 should 子句应该匹配呢? 默认的,不需要匹配任何 should 子句,一种情况例外:如果没有must子句,就必须至少匹配一个should子句。 像我们控制match查询的精度一样,我们也可以通过minimum_should_match参数控制多少should子句需要被匹配,这个参数可以是正整数,也可以是百分比。 GET /my_index/my_type/_search { "query": { "bool": { "should": [ { "match": { "title": "brown" }}, { "match": { "title": "fox" }}, { "match": { "title": "dog" }} ], "minimum_should_match": 2 <1> } } } <1> 这也可以用百分比表示 结果集仅包含title字段中有"brown"和 "fox", "brown"和 "dog", 或 "fox" 和"dog"的文档。如果一个文档包含上述三个条件,那么它的相关性就会比其他仅包含三者中的两个条件的文档要高。 13.3 match匹配怎么当成布尔查询来使用 到现在为止,你可能已经意识到在一个布尔查询中多字段match查询仅仅包裹了已经生成的term查询。通过默认的or操作符,每个term查询都会像一个should子句一样被添加,只要有一个子句匹配就可以了。下面的两个查询是等价的: { "match": { "title": "brown fox"} } { "bool": { "should": [ { "term": { "title": "brown" }}, { "term": { "title": "fox" }} ] } } 通过and操作符,所有的term查询会像must子句一样被添加,因此所有的子句都必须匹配。下面的两个查询是等价的: { "match": { "title": { "query": "brown fox", "operator": "and" } } } { "bool": { "must": [ { "term": { "title": "brown" }}, { "term": { "title": "fox" }} ] } } 如果minimum_should_match参数被指定,match查询就直接被转换成一个bool查询,下面两个查询是等价的: { "match": { "title": { "query": "quick brown fox", "minimum_should_match": "75%" } } } { "bool": { "should": [ { "term": { "title": "brown" }}, { "term": { "title": "fox" }}, { "term": { "title": "quick" }} ], "minimum_should_match": 2 <1> } } <1>因为只有三个子句,所以 minimum_should_match参数在match查询中的值75%就下舍到了2。3个should子句中至少有两个子句匹配。 当然,我们通常写这些查询类型的时候还是使用match查询的,但是理解match查询在内部是怎么工作的可以让你在任何你需要使用的时候更加得心应手。有些情况仅仅使用一个match查询是不够的,比如给某些查询词更高的权重。这种情况我们会在下一节看个例子。 13.4 提高查询得分 当然,bool查询并不仅仅是组合多个简单的一个词的match查询。他可以组合任何其他查询,包括bool查询。bool查询通常会通过组合几个不同查询的得分为每个文档调整相关性得分。 假设想查找关于”full-text search”的文档,但是我们又想给涉及到“Elasticsearch”或者“Lucene”的文档更高的权重。我们的用意是想涉及到”Elasticsearch” 或者 “Lucene”的文档的相关性得分会比那些没有涉及到的文档的得分要高,也就是说这些文档会出现在结果集更靠前的位置。 一个简单的bool查询允许我们写出像下面一样的非常复杂的逻辑: GET /_search { "query": { "bool": { "must": { "match": { "content": { (1) "query": "full text search", "operator": "and" } } }, "should": [ (2) { "match": { "content": "Elasticsearch" }}, { "match": { "content": "Lucene" }} ] } } } content字段必须包含full,text,search这三个单词。 如果content字段也包含了“Elasticsearch”或者“Lucene”,则文档会有一个更高的得分。 匹配的should子句越多,文档的相关性就越强。到目前为止一切都很好。但是如果我们想给包含“Lucene”一词的文档比较高的得分,甚至给包含“Elasticsearch”一词更高的得分要怎么做呢? 同时可以在任何查询子句中指定一个boost值来控制相对权重,默认值为1。一个大于1的boost值可以提高查询子句的相对权重。因此我们可以像下面一样重写之前的查询: GET /_search { "query": { "bool": { "must": { "match": { (1) "content": { "query": "full text search", "operator": "and" } } }, "should": [ { "match": { "content": { "query": "Elasticsearch", "boost": 3 (2) } }}, { "match": { "content": { "query": "Lucene", "boost": 2 (3) } }} ] } } } 这些查询子句的boost值为默认值1。 这个子句是最重要的,因为他有最高的boost值。 这个子句比第一个查询子句的要重要,但是没有“Elasticsearch”子句重要。 注意: boost参数用于提高子句的相对权重(boost值大于1)或者降低子句的相对权重(boost值在0-1之间),但是提高和降低并非是线性的。换句话说,boost值为2并不能够使结果变成两倍的得分。 另外,boost值被使用了以后新的得分是标准的。每个查询类型都会有一个独有的标准算法,算法的详细内容并不在本书的范畴。简单的概括一下,一个更大的boost值可以得到一个更高的得分。 如果你自己实现了没有基于TF/IDF的得分模型,但是你想得到更多的对于提高得分过程的控制,你可以使用function_score查询来调整一个文档的boost值而不用通过标准的步骤。 13.5 分析控制 查询只能查找在倒排索引中出现的词,所以确保在文档索引的时候以及字符串查询的时候使用同一个分析器是很重要的,为了查询的词能够在倒排索引中匹配到。 尽管我们说文档中每个字段的分析器是已经定好的。但是字段可以有不同的分析器,通过给那个字段配置一个指定的分析器或者直接使用类型,索引,或节点上的默认分析器。在索引的时候,一个字段的值会被配置的或者默认的分析器分析。 举个例子,让我们添加一个字段到my_index: PUT /my_index/_mapping/my_type { "my_type": { "properties": { "english_title": { "type": "string", "analyzer": "english" } } } } 现在我们可以通过analyzeAPI分析Foxes词来比较english_title字段中的值以及title字段中的值在创建索引的时候是怎么被分析的: GET /my_index/_analyze?field=my_type.title <1> Foxes GET /my_index/_analyze?field=my_type.english_title <2> Foxes <1> 使用standard分析器的title字段将会返回词foxes。 <2> 使用english分析器的english_title字段将会返回词fox。 这意味着,如果我们为精确的词fox执行一个低级别的term查询,english_title字段会匹 配而title字段不会。 像match查询一样的高级别的查询可以知道字段的映射并且能够在被查询的字段上使用正确的分析器。我们可以在validate-query API的执行中看到这个: GET /my_index/my_type/_validate/query?explain { "query": { "bool": { "should": [ { "match": { "title": "Foxes"}}, { "match": { "english_title": "Foxes"}} ] } } } 它会返回explanation: (title:foxes english_title:fox) match查询为每个字段使用合适的分析器用来确保在那个字段上可以用正确的格式查询这个词。 默认分析器 虽然我们可以在字段级别指定一个分析器,但是如果我们在字段级别没有指定分析器的话,那要怎么决定某个字段使用什么分析器呢? 分析器可以在好几个地方设置。Elasticsearch会查找每个级别直到找到它可以使用的分析器。在创建索引的时候,Elasticsearch查找分析器的顺序如下: 在映射文件中指定字段的analyzer,或者 在文档的_analyzer字段上指定分析器,或者 在映射文件中指定类型的默认分析器analyzer 在索引映射文件中设置默认分析器default 在节点级别设置默认分析器default standard分析器 查找索引的时候,Elasticsearch查找分析器的顺序稍微有点不一样: 在查询参数中指定analyzer,或者 在映射文件中指定字段的analyzer,或者 在映射文件中指定类型的默认分析器analyzer 在索引映射文件中设置默认分析器default 在节点级别设置默认分析器default standard分析器 提示: 上面列表中用斜体字的两行突出了创建索引以及查询索引的时候Elasticsearch查找分析器的区别。_analyzer字段允许你为每个文档指定默认的分析器(比如, english, french, spanish),虽然在查询的时候指定analyzer参数,但是在一个索引中处理多种语言这并不是一个好方法,因为在多语言环境下很多问题会暴露出来。 有时候,在创建索引与查询索引的时候使用不同的分析器也是有意义的。举个例子:在创建索引的时候想要索引同义词 (比如, 出现quick的时候,我们也索引 fast, rapid, 和 speedy)。但是在查询索引的时候,我们不需要查询所有的同义词,我们只要查询用户输入的一个单词就可以了,它可以是quick, fast, rapid, 或者 speedy。 为了满足这种差异,Elasticsearch也支持index_analyzer 和 search_analyzer 参数,并且分析器被命名为default_index和default_search。 把这些额外的参数考虑进去,Elasticsearch查找所有的分析器的顺序实际上像下面的样子: 在映射文件中指定字段的index_analyzer,或者 在映射文件中指定字段的analyzer,或者 在文档的_analyzer字段上指定分析器,或者 在映射文件中指定类型的创建索引的默认分析器index_analyzer 在映射文件中指定类型的默认分析器analyzer 在索引映射文件中设置创建索引的默认分析器default_index 在索引映射文件中设置默认分析器default 在节点级别设置创建索引的默认分析器default_index 在节点级别设置默认分析器default standard分析器 以及查询索引的时候: 在查询参数中指定analyzer,或者 在映射文件中指定字段的search_analyzer,或者 在映射文件中指定字段的analyzer,或者 在映射文件中指定类型的查询索引的默认分析器analyzer 在索引映射文件中设置查询索引的默认分析器default_search 在索引映射文件中设置默认分析器default_search 在节点级别设置查询索引的默认分析器default_search 在节点级别设置默认分析器default standard 分析器 实际配置分析器 可以指定分析器的地方实在是太多了,但实际上,指定分析器很简单。 用索引配置,而不是用配置文件 第一点要记住的是,尽管开始使用Elasticsearch仅仅只是为了一个简单的目的或者是一个应用比如日志,但很可能你会发现更多的案例,结局是在同一个集群中运行着好几个不同的应用。每一个索引都需要是独立的,并且可以被独立的配置。你不要想着给一个案例设置默认值,但是不得不重写他们来适配后面的案例。 这个规则把节点级别的配置分析器方法排除在外了。另外,节点级别的分析器配置方法需要改变每个节点的配置文件并且重启每个节点,这将成为维护的噩梦。保持Elasticsearch持续运行并通过API来管理索引的设置是一个更好的方法。 保持简便性 大多数时间,你可以预先知道文档会包含哪些字段。最简单的方法是在你创建索引或者添加类型映射的时候为每一个全文检索字段设置分析器。虽然这个方法有点啰嗦,但是它可以很容易的看到哪个字段应用了哪个分析器。 通常情况下,大部分的字符串字段是确切值not_analyzed字段(索引但不分析字段)比如标签,枚举,加上少数全文检索字段会使用默认的分析器,像standard 或者 english 或者其他语言。然后你可能只有一到两个字段需要定制分析:或许title字段需要按照你查找的方式去索引来支持你的查找。(指的是你查找的字符创用什么分析器,创建索引就用什么分析器) 你可以在索引设置default分析器的地方为几乎所有全文检索字段设置成你想要的分析器,并且只要在一到两个字段指定专门的分析器。如果,在你的模型中,你每个类型都需要不同的分析器,那么在类型级别使用analyzer配置来代替。 提示: 一个普通的像日志一样的基于时间轴的工作流数据每天都得创建新的索引,忙着不断的创建索引。虽然这种工作流阻止你预先创建索引,但是你可以使用索引模板来指定新的索引的配置和映射。 13.6 关联失效 在讨论多字段检索中的更复杂的查询前,让我们顺便先解释一下为什么我们只用一个主分片来创建索引。 有时有的新手会开一个问题说通过相关性排序没有效果,并且提供了一小段复制的结果:该用户创建了一些文档,执行了一个简单的查询,结果发现相关性较低的结果排在了相关性较高的结果的前面。 为了理解为什么会出现这样的结果,我们假设用两个分片创建一个索引,以及索引10个文档,6个文档包含词 foo,这样可能会出现分片1中有3个文档包含 foo,分片2中也有三个文档包含 foo。换句话说,我们的文档做了比较好的分布式。 在相关性介绍这一节,我们描述了Elasticsearch默认的相似算法,叫做词频率/反转文档频率(TF/IDF)。词频率是一个词在我们当前查询的文档的字段中出现的次数。出现的次数越多,相关性就越大。反转文档频率指的是该索引中所有文档数与出现这个词的文件数的百分比,词出现的频率越大,IDF越小。 然而,由于性能问题,Elasticsearch不通过索引中所有的文档计算IDF。每个分片会为分片中所有的文档计算一个本地的IDF取而代之。 因为我们的文档做了很好的分布式,每个分片的IDF是相同的。现在假设5个包含foo的文档在分片1中,以及其他6各文档在分片2中。在这个场景下,词foo在第一个分片中是非常普通的(因此重要性较小),但是在另一个分片中是很稀少的(因此重要性较高)。这些区别在IDF中就会产生不正确的结果。 事实证明,这并不是一个问题。你索引越多的文档,本地IDF和全局IDF的区别就会越少。在实际工作的数据量下,本地IDF立刻能够很好的工作(With real-world volumes of data, the local IDFs soon even out,不知道这么翻译合不合适)。所以问题不是因为关联失效,而是因为数据太少。 为了测试的目的,对于这个问题,有两种方法可以奏效。第一种方法是创建一个只有一个主分片的索引,像我们介绍match查询那节一样做。如果你只有一个分片,那么本地IDF就是全局IDF。 第二种方法是在你们请求中添加?search_type=dfs_query_then_fetch。dfs就是Distributed Frequency Search,并且它会告诉Elasticsearch检查每一个分片的本地IDF为了计算整个索引的全局IDF。 第十四章 多字段搜索 只有一个简单的match子句的查询是很少的。我们经常需要在一个或者多个字段中查询相同的或者不同的 查询字符串,意味着我们需要能够组合多个查询子句以及使他们的相关性得分有意义。 或许我们在寻找列夫·托尔斯泰写的一本叫《战争与和平》的书。或许我们在Elasticsearch的文档中查找minimum should match,它可能在标题中,或者在一页的正文中。或许我们查找名为John,姓为Smith的人。 在这一章节,我们会介绍用于构建多个查询子句搜索的可能的工具,以及怎么样选择解决方案来应用到你特殊的场景。 14.1 多重查询字段 在明确的字段中的词查询是最容易处理的多字段查询。如果我们知道War and Peace是标题,Leo Tolstoy是作者,可以很容易的用match查询表达每个条件,并且用布尔查询组合起来: GET /_search { "query": { "bool": { "should": [ { "match": { "title": "War and Peace" }}, { "match": { "author": "Leo Tolstoy" }} ] } } } 布尔查询采用越多匹配越好的方法,所以每个match子句的得分会被加起来变成最后的每个文档的得分。匹配两个子句的文档的得分会比只匹配了一个文档的得分高。 当然,没有限制你只能使用match子句:布尔查询可以包装任何其他的查询类型,包含其他的布尔查询,我们可以添加一个子句来指定我们更喜欢看被哪个特殊的翻译者翻译的那版书: GET /_search { "query": { "bool": { "should": [ { "match": { "title": "War and Peace" }}, { "match": { "author": "Leo Tolstoy" }}, { "bool": { "should": [ { "match": { "translator": "Constance Garnett" }}, { "match": { "translator": "Louise Maude" }} ] }} ] } } } 为什么我们把翻译者的子句放在一个独立的布尔查询中?所有的匹配查询都是should子句,所以为什么不把翻译者的子句放在和title以及作者的同一级? 答案就在如何计算得分中。布尔查询执行每个匹配查询,把他们的得分加在一起,然后乘以匹配子句的数量,并且除以子句的总数。每个同级的子句权重是相同的。在前面的查询中,包含翻译者的布尔查询占用总得分的三分之一。如果我们把翻译者的子句放在和标题与作者同级的目录中,我们会把标题与作者的作用减少的四分之一。 优选子句 在先前的查询中我们可能不需要使每个子句都占用三分之一的权重。我们可能对标题以及作者比翻译者更感兴趣。我们需要调整查询来使得标题和作者的子句相关性更重要。 最简单的方法是使用boost参数。为了提高标题和作者字段的权重,我们给boost参数提供一个比1高的值: GET /_search { "query": { "bool": { "should": [ { "match": { <1> "title": { "query": "War and Peace", "boost": 2 }}}, { "match": { <1> "author": { "query": "Leo Tolstoy", "boost": 2 }}}, { "bool": { <2> "should": [ { "match": { "translator": "Constance Garnett" }}, { "match": { "translator": "Louise Maude" }} ] }} ] } } } 标题和作者的boost值为2。 嵌套的布尔查询的boost值为默认的1。 给boost参数一个最好的值可以通过试验和犯错来很容易的决定:设置一个boost值,执行测试查询,重复上述过程。一个合理的boost值在1-10之间,也可能15。更高的boost值影响会很小,因为分数是标准化得。 14.2 单个查询字符串 布尔查询是多重查询的支柱,它在多数情况下有用,尤其是当你能够将不同查询字符串映射到对应的单一字段时。 问题在于,用户期望把他们所有的搜索项放到一个单独字段中去查询。并且期望这个应用能够得出他们想要的正确的结果。讽刺的是,多字段查询形式是一个高级的——它给用户呈现的形式是高级的,但是执行起来却特别简单。 对于多词,多字段查询,没有一种简单的一个通用的途径。要获得最适合的结果,你必须对你的数据有足够的了解,并且知道如何使用合适的工具。 了解你的数据 当你唯一的用户输入一个单个查询字符串,你可能经常会遇到下面三个情形: * Best fields 当搜索一个代表概念的词时,例如“brown fox”,这两个词在一起比它们单独更有意义。而像‘title’,‘body’这些字段,会被认为之间存在竞争。文档在同一个字段上会有许多值,所以得分应该来自最匹配的字段。 * Most fields 一个常用的微调相关性的方法就是为同样的数据索引到多个字段,每一个都有自己的解析链 主要的字段可能包含他们的词根,同义词,和去掉音符或者重音符的词。它用来匹配尽可能多的文档。 同一个文本可能会在其他字段建立索引以提供更加精确的匹配。一个字段可能包含非词根的版本,另一个是带着重音符的原词,第三个可能使用小招牌来提供相似词的信息 这些字段作为匹配文档的增加相关性得分标记,匹配的字段越多,越好。 * Cross fields 对于一些实体对象,标识的信息可能在多个字段之间分布,每个字段组成是其一部分。如下所示。 * Person: ‘first_name’、‘last_name’ * Book:‘title’、‘author’、‘description’ * Address:‘street’、‘city’、‘country’、‘postcode’ 在这种情况下,我们想要找到在任何一个所列字段中找到尽可能多的词。我们需要把多个字段当成一个大的字段,然后在这个字段进行搜索,所有这些都是多词的,多字段的查询,但是每种都使用不同的策略 14.3 最好的字段(Best fields) 假如我们有一个网站,允许用户搜索博客信息,例如下面这两个文档: PUT /my_index/my_type/1 { "title": "Quick brown rabbits", "body": "Brown rabbits are commonly seen." } PUT /my_index/my_type/2 { "title": "Keeping pets healthy", "body": "My quick brown fox eats rabbits on a regular basis." } 用户输入‘Brown fox’,点击搜索。提前我们不知道用户的搜索选项会被宰‘title’或‘body’字段找到,但是用户很有可能在搜索相关的单词。就人眼观察,显然文档2似乎是更好的匹配,因为两个单词被搜索的单词文档2都包含。 现在运行下面的布尔查询: GET /my_index/my_type_second/_search { "query": { "bool": { "should": [ { "match": { "title": "Brown fox" }}, { "match": { "body": "Brown fox" }} ] } } } 结果如下: "hits" : [ { "_index" : "my_index_sencond", "_type" : "my_type", "_id" : "1", "_score" : 0.029836398, "_source" : { "title" : "Quick brown rabbits", "body" : "Brown rabbits are commonly seen." } }, { "_index" : "my_index_sencond", "_type" : "my_type", "_id" : "2", "_score" : 0.01989093, "_source" : { "title" : "Keeping pets healthy", "body" : "My quick brown fox eats rabbits on a regular basis." } } ] 我们发现,这个查询给出文档1的得分更高。 为了理解这是为什么,考虑布尔查询计算得分的步骤: 1.它在should子句里运行两个匹配查询 2.它将两者得分相加 3.乘以总的匹配子句个数 4.除以总的子句个数 文档1在两个字段中都包含‘brown’,因此匹配查询成功获得得分。文档2在body字段中包含‘brown’和‘fox’,但title字段却一个单词都不包含。从body得到的高分,加上从title得到的0分,乘以1/2(它会乘以匹配到文档数目/总文档数目),所以得分就低。 dis_max match查询 现在我们使用dis_max查询或者Disjunction Max Query。Disjunction意思是或(conjunction意思是and)所以Disjunction Max Query查询简单的意思就是:返回任意一个查询匹配成功的文档,并且该文档得分最高: GET /my_index/my_type_second/_search { "query": { "dis_max": { "queries": [ { "match": { "title": "Brown fox" }}, { "match": { "body": "Brown fox" }} ] } } } 这样就返回了我们期望返回的文档了。 14.4 调整Best Field 查询 当用户将搜索内容改成“quick pets”,会发生什么?两个文档中都包含了quick,但是只有文档2中包含了pets。两个文档都没有在同一个字段中全部包含两个搜索词。 一个简单的dis_max查询会挑选出最匹配的字段,并且忽略另外一个: { "query": { "dis_max": { "queries": [ { "match": { "title": "Quick pets" }}, { "match": { "body": "Quick pets" }} ] } } } 这个执行结果中,会得出两个相同得分的文档。 我们期望同时出现在title字段和body字段的文档比只在一个字段出现搜索词的文档的得分更高,但是,显示并非如此。你需要记住的是:dis_max查询只是简单地使用单个匹配得分最高的查询而已。 tie_breaker 然而,同时把其他匹配语句的分数考虑在内也是可行的。你可以通过制定tie_breaker参数来实现 { "query": { "dis_max": { "queries": [ { "match": { "title": "Quick pets" }}, { "match": { "body": "Quick pets" }} ], "tie_breaker": 0.3 } } } tie_breaker参数会使dis_max查询的行为更像dis_max和bool的结合。它会按照下面计算得分: 先获得最匹配的得分 用tie_breaker乘以每个匹配语句的得分 把它们加在一起,然后标准化 通过tie_breaker,所有的匹配语句都会计算,并且最匹配语句得分最高 tie_breaker的值可以设为0-1之间 样例格式

优秀的个人博客,低调大师

《读书报告 – Elasticsearch入门 》----Part II 深入搜索(1)

Part II 深入搜索 搜索不仅仅是全文本搜索:数据的很大部分是结构化的值例如日期、数字。这部分开始解释怎样以一种高效地方式结合结构化搜索和全文本搜索。 第十二章 结构化搜索 结构化搜索_ 是指查询包含内部结构的数据。日期,时间,和数字都是结构化的:它们有明确的格式给你执行逻辑操作。一般包括比较数字或日期的范围,或确定两个值哪个大。 文本也可以被结构化。一包蜡笔有不同的颜色:红色,绿色,蓝色。一篇博客可能被打上 分布式 和 搜索的标签。电子商务产品有商品统一代码(UPCs) 或其他有着严格格式的标识。 通过结构化搜索,你的查询结果始终是 是或非;是否应该属于集合。结构化搜索不关心文档的相关性或分数,它只是简单的包含或排除文档。 这必须是有意义的逻辑,一个数字不能比同一个范围中的其他数字更多。它只能包含在一个范围中 —— 或不在其中。类似的,对于结构化文本,一个值必须相等或不等。这里没有 更匹配 的概念。 12.1 查找准确值 对于准确值,你需要使用过滤器。过滤器的重要性在于它们非常的快。它们不计算相关性(避过所有计分阶段)而且很容易被缓存。我们今后再来讨论过滤器的性能优势【过滤器缓存】,现在,请先记住尽可能多的使用过滤器。 用于数字的 term 过滤器 介绍 term 过滤器,经常会用到它,这个过滤器旨在处理数字,布尔值,日期,和文本。 看一下例子,一些产品最初用数字来索引,包含两个字段 price 和 productID: POST /my_store/products/_bulk { "index": { "_id": 1 }} { "price" : 10, "productID" : "XHDK-A-1293-#fJ3" } { "index": { "_id": 2 }} { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } { "index": { "_id": 3 }} { "price" : 30, "productID" : "JODL-X-1937-#pV7" } { "index": { "_id": 4 }} { "price" : 30, "productID" : "QQPX-R-3956-#aD8" } 目标是找出特定价格的产品。如果有关系型数据库背景,可能用 SQL 来表现这次查询比较熟悉,它看起来像这样: SELECT document FROM products WHERE price = 20 在 Elasticsearch DSL 中,使用 term 过滤器来实现同样的事。term 过滤器会查找设定的准确值。term 过滤器本身很简单,它接受一个字段名和我们希望查找的值: { "term" : { "price" : 20 } } term 过滤器本身并不能起作用。像在【查询 DSL】中介绍的一样,搜索 API 需要得到一个查询语句,而不是一个 过滤器。为了使用 term 过滤器,我们需要将它包含在一个过滤查询语句中: GET /my_store/products/_search { "query" : { "filtered" : { <1> "query" : { "match_all" : {} <2> }, "filter" : { "term" : { <3> "price" : 20 } } } } } <1> filtered 查询同时接受接受 query 与 filter。 <2> match_all 用来匹配所有文档,这是默认行为,所以在以后的例子中将省略掉 query 部分。 <3> 这是上面见过的 term 过滤器。注意它在 filter 分句中的位置。 执行之后,你将得到预期的搜索结果:只能文档 2 被返回了(因为只有 2 的价格是 20): "hits" : [ { "_index" : "my_store", "_type" : "products", "_id" : "2", "_score" : 1.0, <1> "_source" : { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } } ] <1> 过滤器不会执行计分和计算相关性。分值由 match_all 查询产生,所有文档一视同仁,所有每个结果的分值都是 1 用于文本的 term 过滤器 像我们在开头提到的,term 过滤器可以像匹配数字一样轻松的匹配字符串。让我们通过特定 UPC 标识码来找出产品,而不是通过价格。如果用 SQL 来实现,我们可能会使用下面的查询: sql SELECT product FROM products WHERE productID = "XHDK-A-1293-#fJ3" 转到查询 DSL,我们用 term 过滤器来构造一个类似的查询: GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "term" : { "productID" : "XHDK-A-1293-#fJ3" } } } } } 有点出乎意料:没有得到任何结果值!为什么呢?问题不在于 term 查询;而在于数据被索引的方式。如果我们使用 analyze API,我们可以看到 UPC 被分解成短小的表征: curl -XGET '10.10.10.114:9200/my_store_weichao/_analyze?field=productID&pretty' -d'XHDK-A-1293-#fJ3' { "tokens" : [ { "token" : "xhdk", "start_offset" : 0, "end_offset" : 4, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "a", "start_offset" : 5, "end_offset" : 6, "type" : "<ALPHANUM>", "position" : 2 }, { "token" : "1293", "start_offset" : 7, "end_offset" : 11, "type" : "<NUM>", "position" : 3 }, { "token" : "fj3", "start_offset" : 13, "end_offset" : 16, "type" : "<ALPHANUM>", "position" : 4 } ] } 这里有一些需要注意到的要点: 我们得到了四个分开的标记,而不是一个完整的标记来表示UPC。 所有的字符都被转为了小写。 我们失去了连字符和 # 符号。 所以当用 XHDK-A-1293-#fJ3 来查找时,得不到任何结果,因为这个标记不在我们的倒排索引中。相反,那里有上面列出的四个标记。 显然,在处理唯一标识码,或其他枚举值时,这不是我们想要的结果。 为了避免这种情况发生,需要通过设置这个字段为 not_analyzed 来告诉 Elasticsearch 它包含一个准确值。曾在【自定义字段映射】中见过它。为了实现目标,要先删除旧索引(因为它包含了错误的映射),并创建一个正确映射的索引: DELETE /my_store <1> PUT /my_store <2> { "mappings" : { "products" : { "properties" : { "productID" : { "type" : "string", "index" : "not_analyzed" <3> } } } } } <1> 必须首先删除索引,因为我们不能修改已经存在的映射。 <2> 删除后,我们可以用自定义的映射来创建它。 <3> 这里我们明确表示不希望 productID 被分析。 现在我们可以继续重新索引文档: POST /my_store/products/_bulk { "index": { "_id": 1 }} { "price" : 10, "productID" : "XHDK-A-1293-#fJ3" } { "index": { "_id": 2 }} { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } { "index": { "_id": 3 }} { "price" : 30, "productID" : "JODL-X-1937-#pV7" } { "index": { "_id": 4 }} { "price" : 30, "productID" : "QQPX-R-3956-#aD8" } 现在我们的 term 过滤器将按预期工作。让我们在新索引的数据上再试一次(注意,查询和过滤都没有修改,只是数据被重新映射了)。 GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "term" : { "productID" : "XHDK-A-1293-#fJ3" } } } } } productID 字段没有经过分析,term 过滤器也没有执行分析,所以这条查询找到了准确匹配的值,如期返回了文档 1。 内部过滤操作 Elasticsearch 在内部会通过一些操作来执行一次过滤: 查找匹配文档。 term 过滤器在倒排索引中查找词 XHDK-A-1293-#fJ3,然后返回包含那个词的文档列表。在这个例子中,只有文档 1 有我们想要的词。 创建字节集 然后过滤器将创建一个 字节集 —— 一个由 1 和 0 组成的数组 —— 描述哪些文档包含这个词。匹配的文档得到 1 字节,在我们的例子中,字节集将是 [1,0,0,0] 缓存字节集 最后,字节集被储存在内存中,以使我们能用它来跳过步骤 1 和 2。这大大的提升了性能,让过滤变得非常的快。 增加使用次数累积 Elasticsearch能够缓存non-scoring查询,从而让查询访问更快,然而它也会将很少再用的查询缓存起来。因此我们想缓存那些未来会再次用到的查询从而来减少资源的浪费。 当执行 filtered 查询时,filter 会比 query 早执行。结果字节集会被传给 query 来跳过已经被排除的文档。这种过滤器提升性能的方式,查询更少的文档意味着更快的速度。 组合过滤 前面的两个例子展示了单个过滤器的使用。现实中,你可能需要过滤多个值或字段,例如,想在 Elasticsearch 中表达这句 SQL SELECT product FROM products WHERE (price = 20 OR productID = "XHDK-A-1293-#fJ3") AND (price != 30) 这些情况下,需要 bool 过滤器。这是以其他过滤器作为参数的组合过滤器,将它们结合成多种布尔组合。 布尔过滤器 bool 过滤器由三部分组成: { "bool" : { "must" : [], "should" : [], "must_not" : [], } } must:所有分句都必须匹配,与 AND 相同。 must_not:所有分句都必须不匹配,与 NOT 相同。 should:至少有一个分句匹配,与 OR 相同。 这样就行了!如果你需要多个过滤器,将他们放入 bool 过滤器就行。 提示: bool 过滤器的每个部分都是可选的(例如,你可以只保留一个 must 分句),而且每个部分可以包含一到多个过滤器 为了复制上面的 SQL 示例,我们将两个 term 过滤器放在 bool 过滤器的 should 分句下,然后用另一个分句来处理 NOT 条件: GET /my_store/products/_search { "query" : { "filtered" : { <1> "filter" : { "bool" : { "should" : [ { "term" : {"price" : 20}}, <2> { "term" : {"productID" : "XHDK-A-1293-#fJ3"}} <2> ], "must_not" : { "term" : {"price" : 30} <3> } } } } } } <1> 注意我们仍然需要用 filtered 查询来包裹所有条件。 <2> 这两个 term 过滤器是 bool 过滤器的子节点,因为它们被放在 should 分句下,所以至少他们要有一个条件符合。 <3> 如果一个产品价值 30,它就会被自动排除掉,因为它匹配了 must_not 分句。 我们的搜索结果返回了两个结果,分别满足了 bool 过滤器中的不同分句: "hits" : [ { "_id" : "1", "_score" : 1.0, "_source" : { "price" : 10, "productID" : "XHDK-A-1293-#fJ3" <1> } }, { "_id" : "2", "_score" : 1.0, "_source" : { "price" : 20, <2> "productID" : "KDKE-B-9947-#kL5" } } ] <1> 匹配 term 过滤器 productID = "XHDK-A-1293-#fJ3" <2> 匹配 term 过滤器 price = 20 嵌套布尔过滤器 虽然 bool 是一个组合过滤器而且接受子过滤器,需明白它自己仍然只是一个过滤器。这意味着你可以在 bool 过滤器中嵌套 bool 过滤器,实现更复杂的布尔逻辑。 下面先给出 SQL 语句: SELECT document FROM products WHERE productID = "KDKE-B-9947-#kL5" OR ( productID = "JODL-X-1937-#pV7" AND price = 30 ) 可以将它翻译成一对嵌套的 bool 过滤器: GET /my_store/products/_search { "query" : { "constant_score" : { "filter" : { "bool" : { "should" : [ { "term" : {"productID" : "KDKE-B-9947-#kL5"}}, <1> { "bool" : { <1> "must" : [ { "term" : {"productID" : "JODL-X-1937-#pV7"}}, <2> { "term" : {"price" : 30}} <2> ] }} ] } } } } } <1> 因为term和bool在should中的bool过滤器中,因此至少term和bool其中一个查询必须被匹配。 <2> 这两个term过滤器在bool查询的must中匹配嵌套,因此必须全部匹配。 结果得到两个文档,分别匹配一个 should 分句: "hits" : { "total" : 2, "max_score" : 1.0, "hits" : [ { "_index" : "my_store_weichao", "_type" : "products", "_id" : "2", "_score" : 1.0, "_source" : { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } }, { "_index" : "my_store_weichao", "_type" : "products", "_id" : "3", "_score" : 1.0, "_source" : { "price" : 30, "productID" : "JODL-X-1937-#pV7" } } ] 这只是一个简单的例子,但是它展示了该怎样用布尔过滤器来构造复杂的逻辑条件。 查询多个准确值 term 过滤器在查询单个值时很好用,但是你可能经常需要搜索多个值。比如你想寻找 20 或 30 元产品的文档,该怎么做呢? 比起使用多个 term 过滤器,你可以用一个 terms 过滤器。terms 过滤器是 term 过滤器的复数版本。 它用起来和 term 差不多,我们现在来指定一组数值,而不是单一价格: { "terms" : { "price" : [20, 30] } } 像 term 过滤器一样,我们将它放在 filtered 查询中: GET /my_store/products/_search { "query" : { "constant_score" : { "filter" : { "terms" : { "price" : [20, 30] } } } } } <1> 这是前面提到的 terms 过滤器,放置在 包含在constant_score的filtered 查询中这条查询将返回第二,第三和第四个文档: 包含,而不是相等 理解 term 和 terms 是包含操作,而不是相等操作,这点非常重要。 假如你有一个 term 过滤器 { "term" : { "tags" : "search" } },它将匹配下面两个文档: { "tags" : ["search"] } { "tags" : ["search", "open_source"] } <1> <1> 虽然这个文档除了 search 还有其他短语,它还是被返回了 回顾一下 term 过滤器是怎么工作的:它检查倒排索引中所有具有短语的文档,然后组成一个字节集。在我们简单的示例中,我们有下面的倒排索引: Token DocIDs open_source 2 search 1,2 当执行 term 过滤器来查询 search 时,它直接在倒排索引中匹配值并找出相关的 ID。如你所见,文档 1 和文档 2 都包含 search,所以他们都作为结果集返回。 提示: 倒排索引的特性让完全匹配一个字段变得非常困难。你将如何确定一个文档只能包含你请求的短语?你将在索引中找出这个短语,解出所有相关文档 ID,然后扫描 索引中每一行来确定文档是否包含其他值。 由此可见,这将变得非常低效和开销巨大。因此,term 和 terms 是 必须包含 操作,而不是 必须相等。 完全匹配 假如你真的需要完全匹配这种行为,最好是通过添加另一个字段来实现。在这个字段中,你索引原字段包含值的个数。引用上面的两个文档,我们现在包含一个字段来记录标签的个数: { "tags" : ["search"], "tag_count" : 1 } { "tags" : ["search", "open_source"], "tag_count" : 2 } 一旦你索引了标签个数,你可以构造一个 bool 过滤器来限制短语个数: GET /my_index/my_type/_search { "query": { "constant_score" : { "filter" : { "bool" : { "must" : [ { "term" : { "tags" : "search" } }, <1> { "term" : { "tag_count" : 1 } } <2> ] } } } } } <1> 找出所有包含 search 短语的文档 <2> 但是确保文档只有一个标签 这将匹配只有一个 search 标签的文档,而不是匹配所有包含了 search 标签的文档。 范围 到现在只搜索过准确的数字,现实中,通过范围来过滤更为有用。例如,你可能希望找到所有价格高于 20 元而低于 40 元的产品。 在 SQL 语法中,范围可以如下表示: SELECT document FROM products WHERE price BETWEEN 20 AND 40 Elasticsearch 有一个 range 过滤器,让你可以根据范围过滤: "range" : { "price" : { "gt" : 20, "lt" : 40 } } range 过滤器既能包含也能排除范围,通过下面的选项: gt: > 大于 lt: < 小于 gte: >= 大于或等于 lte: <= 小于或等于 下面是范围过滤器的一个示例: GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "range" : { "price" : { "gte" : 20, "lt" : 40 } } } } } } 假如你需要不设限的范围,去掉一边的限制就可以了: "range" : { "price" : { "gt" : 20 } } 日期范围 range 过滤器也可以用于日期字段: "range" : { "timestamp" : { "gt" : "2014-01-01 00:00:00", "lt" : "2014-01-07 00:00:00" } } 当用于日期字段时,range 过滤器支持日期数学操作。例如,想找到所有最近一个小时的文档: "range" : { "timestamp" : { "gt" : "now-1h" } } 这个过滤器将始终能找出所有时间戳大于当前时间减 1 小时的文档,让这个过滤器像移窗一样通过你的文档。 日期计算也能用于实际的日期,而不是仅仅是一个像 now 一样的占位符。只要在日期后加上双竖线 ||,就能使用日期数学表达式了。 "range" : { "timestamp" : { "gt" : "2014-01-01 00:00:00", "lt" : "2014-01-01 00:00:00||+1M" <1> } } <1> 早于 2014 年 1 月 1 号加一个月 字符串范围 range 过滤器也可以用于字符串。字符串范围根据字典或字母顺序来计算。例如,这些值按照字典顺序排序: 5, 50, 6, B, C, a, ab, abb, abc, b 提示:倒排索引中的短语按照字典顺序排序,也是为什么字符串范围使用这个顺序。 假如我们想让范围从 a 开始而不包含 b,我们可以用类似的 range 过滤器语法: "range" : { "title" : { "gte" : "a", "lt" : "b" } } 当心基数: 数字和日期字段的索引方式让他们在计算范围时十分高效。但对于字符串来说却不是这样。为了在字符串上执行范围操作,Elasticsearch 会在这个范围内的每个短语执行 term 操作。这比日期或数字的范围操作慢得多。 字符串范围适用于一个基数较小的字段,一个唯一短语个数较少的字段。你的唯一短语数越多,搜索就越慢。 12.2 处理 Null 值 回到我们早期的示例,在文档中有一个多值的字段 tags,一个文档可能包含一个或多个标签,或根本没有标签。如果一个字段没有值,它是怎么储存在倒排索引中的? 这是一个取巧的问题,因为答案是它根本没有存储。让我们从看一下前几节的倒排索引: Token DocIDs open_source 2 search 1,2 你怎么可能储存一个在数据结构不存在的字段呢?倒排索引是标记和包含它们的文档的一个简单列表。假如一个字段不存在,它就没有任何标记,也就意味着它无法被倒排索引的数据结构表达出来。 本质上来说,null,[](空数组)和 [null] 是相等的。它们都不存在于倒排索引中! 显然,这个世界却没有那么简单,数据经常会缺失字段,或包含空值或空数组。为了应对这些情形,Elasticsearch 有一些工具来处理空值或缺失的字段。 exists 过滤器 工具箱中的第一个利器是 exists 过滤器,这个过滤器将返回任何包含这个字段的文档,让我们用标签来举例,索引一些示例文档: POST /my_index_weichao/posts/_bulk { "index": { "_id": "1" }} { "tags" : ["search"] } <1> { "index": { "_id": "2" }} { "tags" : ["search", "open_source"] } <2> { "index": { "_id": "3" }} { "other_field" : "some data" } <3> { "index": { "_id": "4" }} { "tags" : null } <4> { "index": { "_id": "5" }} { "tags" : ["search", null] } <5> <1> tags 字段有一个值 <2> tags 字段有两个值 <3> tags 字段不存在 <4> tags 字段被设为 null <5> tags 字段有一个值和一个 null 结果我们 tags 字段的倒排索引看起来将是这样: Token DocIDs open_source 2 search 1,2,5 我们的目标是找出所有设置了标签的文档,我们不关心这个标签是什么,只要它存在于文档中就行。在 SQL 语法中,我们可以用 IS NOT NULL 查询: SELECT tags FROM posts WHERE tags IS NOT NULL 在 Elasticsearch 中,我们使用 exists 过滤器: GET /my_index/posts/_search { "query" : { "filtered" : { "filter" : { "exists" : { "field" : "tags" } } } } } 查询返回三个文档: "hits" : [ { "_id" : "1", "_score" : 1.0, "_source" : { "tags" : ["search"] } }, { "_id" : "5", "_score" : 1.0, "_source" : { "tags" : ["search", null] } <1> }, { "_id" : "2", "_score" : 1.0, "_source" : { "tags" : ["search", "open source"] } } ] <1> 文档 5 虽然包含了一个 null 值,仍被返回了。这个字段存在是因为一个有值的标签被索引了,所以 null 对这个过滤器没有影响 结果很容易理解,所以在 tags 字段中有值的文档都被返回了。只排除了文档 3 和 4。 missing 过滤器 missing 过滤器本质上是 exists 的反义词:它返回没有特定字段值的文档,像这条 SQL 一样: SELECT tags FROM posts WHERE tags IS NULL 让我们在前面的例子中用 missing 过滤器来取代 exists: GET /my_index/posts/_search { "query" : { "filtered" : { "filter": { "missing" : { "field" : "tags" } } } } } 如你所愿,我们得到了两个没有包含标签字段的文档: "hits" : [ { "_id" : "3", "_score" : 1.0, "_source" : { "other_field" : "some data" } }, { "_id" : "4", "_score" : 1.0, "_source" : { "tags" : null } } ] 什么时候 null 才表示 null 有时你需要能区分一个字段是没有值,还是被设置为 null。用上面见到的默认行为无法区分这一点,数据都不存在了。幸运的是,我们可以将明确的 null 值用我们选择的占位符来代替 当指定字符串,数字,布尔值或日期字段的映射时,你可以设置一个 null_value 来处理明确的 null 值。没有值的字段仍将被排除在倒排索引外。 当选定一个合适的 null_value 时,确保以下几点: 它与字段的类型匹配,你不能在 date 类型的字段中使用字符串 null_value 它需要能与这个字段可能包含的正常值区分开来,以避免真实值和 null 值混淆 对象的 exists/missing exists 和 missing 过滤器同样能在内联对象上工作,而不仅仅是核心类型。例如下面的文档: { "name" : { "first" : "John", "last" : "Smith" } } 可以检查 name.first 和 name.last 的存在性,也可以检查 name 的。然而,在【映射】中,我们提到对象在内部被转成扁平化的键值结构,像下面所示: { "name.first" : "John", "name.last" : "Smith" } 所以我们是怎么使用 exists 或 missing 来检测 name 字段的呢,这个字段并没有真正存在于倒排索引中。 原因是像这样的一个过滤器 { "exists" : { "field" : "name" } } 实际是这样执行的 { "bool": { "should": [ { "exists": { "field": { "name.first" }}}, { "exists": { "field": { "name.last" }}} ] } } 同样这意味着假如 first 和 last 都为空,那么 name 就是不存在的。 12.3 关于缓存 在【内部过滤操作】章节中,提到过过滤器是怎么计算的。它们的核心是一个字节集来表示哪些文档符合这个过滤器。Elasticsearch 主动缓存了这些字节集留作以后使用。一旦缓存后,当遇到相同的过滤时,这些字节集就可以被重用,而不需要重新运算整个过滤。 缓存的字节集很“聪明”:他们会增量更新。你索引中添加了新的文档,只有这些新文档需要被添加到已存的字节集中,而不是一遍遍重新计算整个缓存的过滤器。过滤器和整个系统的其他部分一样是实时的,你不需要关心缓存的过期时间。 独立的过滤缓存 每个过滤器都被独立计算和缓存,而不管它们在哪里使用。如果两个不同的查询使用相同的过滤器,则会使用相同的字节集。同样,如果一个查询在多处使用同样的过滤器,只有一个字节集会被计算和重用。 让我们看一下示例,查找符合下列条件的邮箱: 在收件箱而且没有被读取过 不在收件箱但是被标记为重要 "bool": { "should": [ { "bool": { "must": [ { "term": { "folder": "inbox" }}, <1> { "term": { "read": false }} ] }}, { "bool": { "must_not": { "term": { "folder": "inbox" } <1> }, "must": { "term": { "important": true } } }} ] } <1> 这两个过滤器相同,而且会使用同一个字节集。 虽然一个收件箱条件是 must 而另一个是 must_not,这两个条件本身是相等的。这意味着字节集会在第一个条件执行时计算一次,然后作为缓存被另一个条件使用。而第二次执行这条查询时,收件箱的过滤已经被缓存了,所以两个条件都能使用缓存的字节集。 这与查询 DSL 的组合型紧密相关。移动过滤器或在相同查询中多处重用相同的过滤器非常简单。这不仅仅是方便了开发者 —— 对于性能也有很大的提升 控制缓存 大部分直接处理字段的枝叶过滤器(例如 term)会被缓存,而像 bool 这类的组合过滤器则不会被缓存。 【提示】 枝叶过滤器需要在硬盘中检索倒排索引,所以缓存它们是有意义的。另一方面来说,组合过滤器使用快捷的字节逻辑来组合它们内部条件生成的字节集结果,所以每次重新计算它们也是很高效的。 然而,有部分枝叶过滤器,默认不会被缓存,因为它们这样做没有意义: 脚本过滤器: 脚本过滤器的结果不能被缓存因为脚本的意义对于 Elasticsearch 来说是不透明的。 Geo 过滤器: 定位过滤器(我们会在【geoloc】中更详细的介绍),通常被用于过滤基于特定用户地理位置的结果。因为每个用户都有一个唯一的定位,geo 过滤器看起来不太会重用,所以缓存它们没有意义。 日期范围: 使用 now 方法的日期范围(例如 "now-1h"),结果值精确到毫秒。每次这个过滤器执行时,now 返回一个新的值。老的过滤器将不再被使用,所以默认缓存是被禁用的。然而,当 now 被取整时(例如,now/d 取最近一天),缓存默认是被启用的。 有时候默认的缓存测试并不正确。可能你希望一个复杂的 bool 表达式可以在相同的查询中重复使用,或你想要禁用一个 date 字段的过滤器缓存。你可以通过 _cache 标记来覆盖几乎所有过滤器的默认缓存策略 { "range" : { "timestamp" : { "gt" : "2014-01-02 16:15:14" <1> }, "_cache": false <2> } } <1> 看起来我们不会再使用这个精确时间戳 <2> 在这个过滤器上禁用缓存 以后的章节将提供一些例子来说明哪些时候覆盖默认缓存策略是有意义的。 12.4 过滤顺序 在 bool 条件中过滤器的顺序对性能有很大的影响。更详细的过滤条件应该被放置在其他过滤器之前,以便在更早的排除更多的文档。 假如条件 A 匹配 1000 万个文档,而 B 只匹配 100 个文档,那么需要将 B 放在 A 前面。 缓存的过滤器非常快,所以它们需要被放在不能缓存的过滤器之前。想象一下我们有一个索引包含了一个月的日志事件,然而,我们只对近一个小时的事件感兴趣: GET /logs/2014-01/_search { "query" : { "filtered" : { "filter" : { "range" : { "timestamp" : { "gt" : "now-1h" } } } } } } 这个过滤条件没有被缓存,因为它使用了 now 方法,这个值每毫秒都在变化。这意味着我们需要每次执行这条查询时都检测一整个月的日志事件。 我们可以通过组合一个缓存的过滤器来让这变得更有效率:我们可以添加一个含固定时间的过滤器来排除掉这个月的大部分数据,例如昨晚凌晨: "bool": { "must": [ { "range" : { "timestamp" : { "gt" : "now-1h/d" <1> } }}, { "range" : { "timestamp" : { "gt" : "now-1h" <2> } }} ] } <1> 这个过滤器被缓存了,因为它使用了取整到昨夜凌晨 now 条件。 <2> 这个过滤器没有被缓存,因为它没有对 now 取整。 now-1h/d 条件取整到昨夜凌晨,所以所有今天之前的文档都被排除掉了。这个结果的字节集被缓存了,因为 now 被取整了,意味着它只需要每天当昨夜凌晨的值改变时被执行一次。now-1h 条件没有被缓存,因为 now 表示最近一毫秒的时间。然而,得益于第一个过滤器,第二个过滤器只需要检测当天的文档就行。 这些条件的排序很重要。上面的实现能正常工作是因为自从昨晚凌晨条件比最近一小时条件位置更前。假如它们用别的方式组合,那么最近一小时条件还是需要检测所有的文档,而不仅仅是昨夜以来的文档。

优秀的个人博客,低调大师

Nginx从入门到掌握【(第2节(共3节)】

目录: nginx作为web服务器时使用的配置. 网络连接相关的配置: 正文: 一、nginx作为web服务器时使用的配置. 1. http配置段: Syntax: http { ... }Default: —Context: main http{}: 由ngx_http_core_module模块所引入; Documentation: http://nginx.org/en/docs/http/ngx_http_core_module.html#http 2. server配置段: Syntax: server { ... }Default: —Context: http server{}: 由ngx_http_core_module模块所引入; Documentation:http://nginx.org/en/docs/http/ngx_http_core_module.html#server 3. location配置段: Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }location @name { ... }Default: —Context: server, location location{}: 由ngx_http_core_module模块所引入; 4. 配置框架: http{ upstream{ ... } server{ location{ root"/path/to/somedir"; ... }#类似于httpd中的<Location>,用于定义URL与本地文件系统的映射关系; 一个server里面可以指定多个location; locationURL{ if...{ ... } } }#每个server类似于httpd中的一个<VirtualHost>; server{ ... } } 注: http与http相关的指令仅能够放置于http, server, location, upstream, if 上下文,但有些指令仅应用于这5种上下文中的某些之中; 为了区分和方便管理每个server段,常用"include FILE_PATH"引用; 例: http{ ... includeserver.conf;//此处配置文件server.conf使用的是相对路径,是相对于根路径/usr/local/nginx而言的; } 3. 配置指令: 1) server {};作用: 定义一个虚拟主机; server{ listen8080; server_namewww.yangbin.com; root"/Web/html"; } 2) listen 作用: 指定监听的地址和端口; listenADDRESS[:PORT] listenPORT; 3) server_name NAME [...]; 作用: 后面可跟多个主机,名称还可以使用正则表达式(~)或通配符:(~开头)匹配规则: (1) 先做精确匹配检查; (2) 左侧通配符匹配检查:*.yangbin.com (3) 右侧通配符匹配检查:如mail.* (4) 正则表达式匹配检查:如~^.*\.yangbin\.com$ (5) default_server; 例: server{ server_namewww.yangbin.com; } server{ server_name*.yangbin.com; } server{ server_namemail.*; } 4) root path; 作用: 设置资源路径映射,用于指明请求的URL所对应的资源所在的文件系统上的起始路径; 放置范围越大,生效范围越小; 5) location [ = | ~ | ~* | ^~ ] uri {...} location @name { ... }功能:允许根据用户请求的URL来匹配定义的各location,匹配到时,此请求将被相应的location配 置块中的配置所处理,例如做访问控制等功能; 匹配规则: 1) =: 精确匹配检查; 2) ~: 正则表达式模式匹配检查,区分字符大小写; 3) ~*: 正则表达式模块匹配检查,不区分字符大小写; 4) ^~: URI的前半部分匹配,不支持正则表达式; 匹配的优先级:精确匹配(=),^~,~,~*,不带任何符号的location; 即先匹配普通,再匹配正则; 例: server{ listen80; server_namewww.yangbin.com; location/{ root"/Web/html/"; indexindex.htmlindex.htm; } location/p_w_picpaths/{ root"/Web/p_w_picpaths/"; }//上面两行其实表示的完整路径是/Web/p_w_picpaths/p_w_picpaths //目录名后面一定要加"/". location~*\.php${ fcgipass; } } 如: /Web/p_w_picpaths下有个xx.png,访问时: http://10.68.7.223/p_w_picpaths/p_w_picpaths/xx.png即可,注意与第一部分/的那个区分开。 出错可查看相应error日志和access日志; 6) alias path; 作用:用于location配置段,定义路径别名; location/p_w_picpaths/{ root"/Web/web1"; } location/p_w_picpaths/{ alias"/www/pictures"; }//此处访问/p_w_picpaths/xx.html,就是访问的/www/pictures/xx.html. 注: root表示指明路径为对应的location "/" URL;alias表示路径映射, 即location指令后定义的URL是相对于alias所指明的路径而言; 一般情况下,在location /中配置root,在location /other中配置alias是一个好习惯. 例: One.location~^/awstats/{ alias/Web/ } 访问:http://yangbin.com/awstats/ 实际访问的是http://yangbin.com/Web/ First.location~^/awstats/{ #使用alias时目录名后面一定要加“/” alias/Web/awstats/; } 访问:http://yangbin.com/awstats/ 实际访问的是http://yangbin.com/Web/awstats/ Third.location~^/awstats/{ root/Web/; } 访问:http://yangbin.com/awstats/ 实际访问的是http://yangbin.com/web/awstats/ 7)index file; 作用: 设置默认主页面; indexindex.phpindex.html; 8) error_page code [...] [=code] URI | @name 作用: 根据http响应状态码来指明特定的错误页面; error_page404/404_customed.html;//即把404错误的页面设定为我们自己指定的页面; [=code]: 以指明的响应码进行响应,而非默认的原来的响应,默认表示以新资源的响应码为其响应码; 例:在server段配置 server{ ... fastcgi_intercept_errorson; error_page404/309.html;//此处的/309.html是相对于网站根目录而言的,即location/对应的root路径. location/{ root"/web/www"; } } [root@nginxnginx]#ls/Web/www/ 309.htmlindex.html [root@nginxnginx]# 总结:fastcgi_intercept_errors语法:fastcgi_intercept_errors on|off 默认值:fastcgi_intercept_errors off 使用字段:http, server, location 该指令指定是否传递4xx和5xx错误信息到客户端,或允许nginx使用error_page处理错误信息。必须明确在error_page中指定处理方法使这个参数有效。 9) 基于IP的访问控制:allow IP/Network; deny IP/Network; 示例: location/js/{ root/Web/www/; allow10.68.7.0/24; denyall; } 10) 基于用户的访问控制 语法: auth_basic STRING | off;默认值: auth_basic off;配置段: http, server, location, limit_except 默认表示不开启认证,后面如果跟上字符,这些字符会在弹窗中显示。 语法: auth_basic_user_file "/PATH/TO/PASSWORD_FILE";默认值: —配置段: http, server, location, limit_except 可使用相对路径.账号密码文件建议使用htpasswd来创建; htpasswd命令需要安装apache httpd服务获得. 示例: [root@nginxnginx]#whichhtpasswd /usr/bin/htpasswd [root@nginxnginx]#htpasswd--help [root@nginxnginx]#idyangbin uid=1000(yangbin)gid=1000(yangbin)组=1000(yangbin) [root@nginxnginx]#htpasswd-cmconf/htpasswd/.htpasswdyangbin Newpassword: Re-typenewpassword: Addingpasswordforuseryangbin [root@nginxnginx]#ll./htpasswd/-a 总用量4 drwxr-xr-x.2rootroot231月1216:07. drwxr-xr-x.13rootroot1821月1216:06.. -rw-r--r--.1rootroot461月1216:07.htpasswd [root@nginxnginx]#chownnginx:root./htpasswd/.htpasswd [root@nginxnginx]#vimconf/server.conf ... location/p_w_picpaths/{ alias/Web/p_w_picpaths/; auth_basicINPUT_PASSWORD; auth_basic_user_filehtpasswd/.htpasswd; } ... [root@nginxnginx]#./sbin/nginx-sreload 浏览器访问: 完成! 11) https服务实现方法:生成私钥, 生成证书签署请求,并获得证书; 例: server{ listen443ssl; server_namelocalhost; ssl_certificate/usr/local/nginx/ssl/nginx.crt; ssl_certificate_key/usr/local/nginx/ssl/nginx.key; ssl_session_cacheshared:SSL:1m; ssl_session_timeout5m; ssl_ciphersHIGH:!aNULL:!MD5; ssl_prefer_server_cipherson; } https的具体配置过程,我在lvs那一篇博客有写,这里不再重复了. 12) stub_status {on|off} Context: 仅用于location上下文;作用: 主要用于查看Nginx的一些状态信息.本模块默认是不会编译进Nginx的,如果要使用该模块,则要在编译安装Nginx时指定: 例: [root@nginxnginx-1.10.2]#pwd /mnt/tools/nginx-1.10.2 [root@nginxnginx-1.10.2]#./configure--help|egrep"stub" --with-http_stub_status_moduleenablengx_http_stub_status_module [root@nginxnginx-1.10.2]#./configure–with-http_stub_status_module 查看已安装的Nginx是否包含"stub_status"模块: #/usr/local/nginx/sbin/nginx-V 结果示例: server{ listen80; server_nameyangbin.com; location/{ root"/web/www"; stub_statuson; } } [root@nginx~]#curl10.68.7.223 Activeconnections:6 serveracceptshandledrequests 241241431 Reading:0Writing:1Waiting:0 [root@nginx~]# 说明: (1) Active connections: 6 # 当前所有处于打开状态的连接数; (2) server accepts handled requests (3) 241 241 431 241 已经接受过的连接数 241 已经处理过的连接数 431 已经处理过的请求数: 在"保持连接"模式下,请求数量可能会多于连接数量;(4)Reading: 0 Writing:1 Waiting:5 Reading: 正处于接收请求状态的连接数;Nginx 读取到客户端的Header信息数,即连接数; Writing: 请求已经接收完成,正处于处理请求或发送响应的过程中的连接数;Nginx 返回给客户端的Header信息数.即响应数据到客户端的数量; waiting: 保持连接模式,且处于活动状态的连接数; 开启keep-alive的情况下,这个值等于 active – (reading + writing),意思就是Nginx已经处理完成,正在等候下一次请求指令的驻留连接.13) rewrite regex replacement flags; 作用:路由重写是Web服务器中的一个很重要的基本功能。通过路由重写,可以结构化URL,更具语义化(对SEO有益)。另外,分享出去的URL可能会因程序路由变动而导致URL失效,而路由的重写可以很好的解决这类问题。regex: 用于匹配URI的正则表达式。使用括号"()"标记要截取的内容。使用环境:server, location, if注:该指令根据表达式来重定向URI,或者修改字符串。指令根据配置文件中的顺序来执行。注意重写表达式只对相对路径有效; 例: rewrite^/p_w_picpaths/(.*\.jpg)$/imgs/$1break; http://www.magedu.com/p_w_picpaths/a/b/c/1.jpg-->/imgs/a/b/c/1.jpg flags: 1) last: 一旦此rewrite规则重写完成后,就不再被后面其他的rewrite规则进行处理,而是由User Agent重新对重写后的URL再一次发起请求,并从头开始执行类似的过程; 2) break: 一旦此rewrite规则重写完成后,由User Agent对新的URL重新发起请求,且不会再被当前location内的任何rewrite规则所检查; 3) redirect: 以302响应码(临时重定向)返回新的URL. 4) permanent: 以301响应码(永久重定向)返回新的URL; 14) if 语法: if (condition){...} 应用环境: server, location condition:(1) 变量名: 变量值为空串,或者以"0"开始,则为false; 其他的均为true; (2) 以变量为操作数构成的比较表达式; 可使用=,!=类似的比较操作符进行测试;(3) 正则表达式的模式匹配操作: ~: 区分大小写的模式匹配检查; ~*: 不区分大小写的模式匹配检查; !~和!~*: 对上面两种测试取反; (4) 测试路径为文件可能性: -f, !-f (5) 测试指定路径为目录的可能性: (6) 测试文件的存在性: -e, !-e (7) 检查文件是否有执行权限: -x, !-x 例如: if($http_user_agent~*MSIE){ rewrite^(.*)$/msie/$1break; } 15) 图片防盗链; 语法: valid_referers none | blocked | server_names | string ...;默认值: —配置段: server, location作用: 指定合法的来源'referer',它决定了内置变量$invalid_referer的值,如果referer头部包含在这个合法网址里面,这个变量被设置为0,否则设置为1.此变量不区分大小写. 参数说明: none: "Referer"来源头部为空的情况blocked: "Referer"来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头.server_names: "Referer"来源头部包含当前的server_names(当前域名)arbitrary string: 任意字符串,定义服务器名或者可选的URI前缀.主机名可以使用*开头或者结尾,在检测来源头部这个过程中,来源域名中的主机端口将会被忽略掉regular expression: 正则表达式,~表示排除https://或http://开头的字符串. location~*\.(jpg|gif|jpeg|png)${ valid_referernoneblockedwww.yangbin.com; if($invalid_referer){ rewrite^/http://www.yangbin.com/403.html; } 16) 定制访问日志格式; log_formatmain'$remote_addr-$remote_user[$time_local]"$request"' '$status$body_bytes_sent"$http_referer"' '"$http_user_agent""$http_x_forwarded_for"'; access_loglogs/access.logmain; 注意:此处可用变量为nginx各模块内建变量; 二、网络连接相关的配置: 1. keepalive_timeout TIME; 长连接的超时时长,默认是75s; 2. keepalive_requests N; 在一个长连接上所能允许请求的最大资源数; 3. keepalive_disable [msie6|safari|none]; 位指定类型的User Agent禁用长连接; 4. tcp_nodelay on|off; 是否对长连接使用TCP_NODELAY选项; 5. client_header_timeout TIME; 读取http请求报文首部的超时时长; 6. client_body_timeout TIME; 读取http请求报文body部分的超时时长; 7. send_timeout TIME; 发送响应报文的超时时长; --- 第二部分完成!

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册