ElasticSearch搜索
最基础的搜索:
curl -XGET http://localhost:9200/_search
返回的结果为:
{ "took": 2, "timed_out": false, "_shards": { "total": 16, "successful": 16, "failed": 0 }, "hits": { "total": 13, "max_score": 1, "hits": [ { "_index": ".kibana", "_type": "config", "_id": "5.5.1", "_score": 1, "_source": { "buildNum": 15405 } }, { "_index": "people", "_type": "man", "_id": "8", "_score": 1, "_source": { "name": "deda", "age": 31, "job": "stu" } }, { "_index": "people", "_type": "man", "_id": "30", "_score": 1, "_source": { "name": "tomi", "age": 19, "job": "master" } }, { "_index": "people", "_type": "man", "_id": "5", "_score": 1, "_source": { "name": "ming", "age": 33, "job": "coding", "like": "football", "tel": "122334" } }, { "_index": "people", "_type": "man", "_id": "2", "_score": 1, "_source": { "name": "fukk", "age": 30, "job": "stu" } }, { "_index": "people", "_type": "man", "_id": "4", "_score": 1, "_source": { "name": "mask", "age": 40, "job": "CEO" } }, { "_index": "people", "_type": "man", "_id": "6", "_score": 1, "_source": { "name": "nan", "age": 25, "job": "coding" } }, { "_index": "peoples", "_type": "employee", "_id": "2", "_score": 1, "_source": { "first_name": "Jane", "last_name": "Smith", "age": 32, "about": "I like to collect rock albums", "interests": [ "music" ] } }, { "_index": "megacorp", "_type": "employee", "_id": "1", "_score": 1, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } }, { "_index": "people", "_type": "man", "_id": "1", "_score": 1, "_source": { "name": "ahaii", "age": 27, "job": "coding" } } ] } }
索引所有文档,返回结果中默认显示前十条数据。
hits:
返回结果中最重要的部分是 hits ,它 包含 total 字段来表示匹配到的文档总数,并且一个 hits 数组包含所查询结果的前十个文档。
在 hits 数组中每个结果包含文档的 _index 、 _type 、 _id ,加上 _source 字段。这意味着我们可以直接从返回的搜索结果中使用整个文档。这不像其他的搜索引擎,仅仅返回文档的ID,需要你单独去获取文档。
每个结果还有一个 _score ,它衡量了文档与查询的匹配程度。默认情况下,首先返回最相关的文档结果,就是说,返回的文档是按照 _score 降序排列的。在这个例子中,我们没有指定任何查询,故所有的文档具有相同的相关性,因此对所有的结果而言 1 是中性的 _score 。
took:
took
值表示执行整个搜索请求耗费了多少毫秒。
shards:
_shards
部分告诉我们在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。正常情况下我们不希望分片失败,但是分片失败是可能发生的。如果我们遭遇到一种灾难级别的故障,在这个故障中丢失了相同分片的原始数据和副本,那么对这个分片将没有可用副本来对搜索请求作出响应。假若这样,Elasticsearch 将报告这个分片是失败的,但是会继续返回剩余分片的结果。
不同索引、不同类型的搜索:
/_search
在所有的索引中搜索所有的类型
/gb/_search
在 gb
索引中搜索所有的类型
/gb,us/_search
在 gb
和 us
索引中搜索所有的文档
/g*,u*/_search
在任何以 g
或者 u
开头的索引中搜索所有的类型
/gb/user/_search
在 gb
索引中搜索 user
类型
/gb,us/user,tweet/_search
在 gb
和 us
索引中搜索 user
和 tweet
类型
/_all/user,tweet/_search
在所有的索引中搜索 user
和 tweet
类型
当在单一的索引下进行搜索的时候,Elasticsearch 转发请求到索引的每个分片中,可以是主分片也可以是副本分片,然后从每个分片中收集结果。多索引搜索恰好也是用相同的方式工作的--只是会涉及到更多的分片。
搜索一个索引有五个主分片和搜索五个索引各有一个分片准确来所说是等价的。
搜索结果分页:
和 SQL 使用 LIMIT
关键字返回单个 page
结果的方法相同,Elasticsearch 接受 from
和 size
参数:
size
- 显示应该返回的结果数量,默认是
10
from
- 显示应该跳过的初始结果数量,默认是
0
显示3条搜索结果:
curl -XGET http://localhost:9200/_search?size=3
显示第4-6条搜索结果:
curl -XGET http://localhost:9200/_search?size=3&from=3
显示第7-9条搜索结果:
curl -XGET http://localhost:9200/_search?size=3&from=6
ElasticSearh搜索API的形式:
1、在查询字符串中传递参数
查询man类型(表)中所有name字段为ahaii的文档:
curl -XGET http://localhost:9200/_all/man/_search?q=name:ahaii
搜索结果如下:
{ "took": 1, "timed_out": false, "_shards": { "total": 16, "successful": 16, "failed": 0 }, "hits": { "total": 1, "max_score": 0.6931472, "hits": [ { "_index": "people", "_type": "man", "_id": "1", "_score": 0.6931472, "_source": { "name": "ahaii", "age": 27, "job": "coding" } } ] } }
2、使用请求体查询
使用请求体查询时,如ElasticSearch系列第一片中介绍。
如果查询多个不同的字段,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引。
例如,在索引一个包含如下字段的文档时:
{ "name": "tim", "job": "CEO", "age": "25" }
这就好似增加了一个名叫 _all
的额外字段,来检索下面这个字符串:
tim CEO 25
除非设置特定字段,否则查询字符串就使用 _all
字段进行搜索。
ElasticSearch中将数据分为两类,精确值(词条 term)和全文。
精确值很容易查询。结果是二进制的:要么匹配查询,要么不匹配。这种数据的查询方式很想关系型数据库中的SQL语句。
精确值查询需要完全匹配,即字符的大小写,字符的数量和位置都是相同的,词条(term)查询使用字符的完全匹配方式进行文本搜索,词条查询不会分析(analyze)查询字符串,给定的字段必须完全匹配词条查询中指定的字符串。由于词条查询的字符串是未经分析(analyzed)的词条,因此,词条查询经常用于结构化的数据,例如,数值,日期等,
全文查询数据要微妙的多。我们问的不只是“这个文档匹配查询吗”,而是“该文档匹配查询的程度有多大?”换句话说,该文档与给定查询的相关性如何?
为了促进这类在全文域中的查询,Elasticsearch 首先分析文档,之后根据结果创建倒排索引 。
倒排索引:
阅读这片博文:http://blog.csdn.net/hguisu/article/details/7962350
为了获取到等多的相关文档,在分词的时候,还需要对单词做一些其他操作。如果我们将词条规范为标准模式,那么我们可以找到与用户搜索的词条不完全一致,但具有足够相关性的文档,比如:
1、忽略关键词的大小写
2、忽略关键词的单复数形式
3、模糊匹配词意相同或相近
单词分析与过滤
ElasticSearch中,分词和标准化的过程就是分析的过程。
分析包含以下两个过程:
1、将一块文本分成适合于倒排索引的独立的词条
2、将这些词条统一化为标准格式以提高它们的“可搜索性”
以上工作由分析器完成。分析器实际上是由三个功能组成:
1、字符串过滤器:
首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 &
转化成 `and`。
2、分词器:
其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
3、Token过滤器:
最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick
),删除词条(例如, 像 a`, `and`, `the
等无用词),或者增加词条(例如,像 jump
和 leap
这种同义词)。
ElasticSearch内置分析器种类:
每种分析器对字符串的处理方式不同,以语句"Set the shape to semi-transparent by calling set_trans(5)"为例:
1、标准分词器:
标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。它会产生:
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
2、简单分析器:
简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生:
set, the, shape, to, semi, transparent, by, calling, set, trans
3、空格分析器:
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
4、语言分析器:
特定语言分析器可用于很多语言。它们可以考虑指定语言的特点。例如, 英语
分析器附带了一组英语无用词(常用单词,例如 and
或者 the
,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的词干 。
英语
分词器会产生下面的词条:
set, shape, semi, transpar, call, set_tran, 5
注意,transparent、 calling
和 set_trans
已经变为词根格式。
当全文查询时,es会对查询字符串做同样的分析处理,以保证搜索的词条格式与索引中的词条格式保持一致。
当精确查询时,es不会分析查询字符串,而是查询匹配到的精确值。
测试分析器:
为了理解es内部是分词的过程,可以使用 analyze
API 测试分析器来看文本是如何被分析的。在消息体里,指定分析器和要分析的文本:
curl -XGET http://localhost:9200/_analyze { "analyzer": "standard", "text": "hello this is my blog." }
可以得到以下结果:
{ "tokens": [ { "token": "hello", "start_offset": 0, "end_offset": 5, "type": "<ALPHANUM>", "position": 0 }, { "token": "this", "start_offset": 6, "end_offset": 10, "type": "<ALPHANUM>", "position": 1 }, { "token": "is", "start_offset": 11, "end_offset": 13, "type": "<ALPHANUM>", "position": 2 }, { "token": "my", "start_offset": 14, "end_offset": 16, "type": "<ALPHANUM>", "position": 3 }, { "token": "blog", "start_offset": 17, "end_offset": 21, "type": "<ALPHANUM>", "position": 4 } ] }
结果中,token是实际存储到索引中的词条,position
指明词条在原始文本中出现的位置。 start_offset
和 end_offset
指明字符在原始字符串中的位置。
映射
为了能够将时间域视为时间,数字域视为数字,字符串域视为全文或精确值字符串, Elasticsearch 需要知道每个域中数据的类型。这个信息包含在映射中。
ElasticSearch中核心域类型:
1、字符串:string
2、整型:byte,short,long,integer
3、浮点:float,double
4、布尔:boolean
5、日期:date
自定义映射:
域里最重要的属性是type,对于不是string的域,一般只需要设置type:
{ "age": { "type": "integer" } }
默认, string
类型域会被认为包含全文。就是说,它们的值在索引前,会通过 一个分析器,针对于这个域的查询在搜索前也会经过一个分析器。
string
域映射的两个最重要 属性是 index
和 analyzer
。
index:
1、analyzed:
首先分析字符串,然后索引它。换句话说,以全文索引这个域。
2、not_analyzed:
索引这个域,所以它能够被搜索,但索引的是精确值。不会对它进行分析。
3、no:
不索引这个域。这个域不会被搜索到。
string
域 index
属性默认是 analyzed
。如果我们想映射这个字段为一个精确值(不分析,精确匹配),我们需要设置它为 not_analyzed:
{ "tag": { "type": "string", "index": "not_analyzed" } }
注意,只有string域可以被分析,像其他如long、double、date类型,永远不会被分析。
analyzer:
对于 analyzed
字符串域,用 analyzer
属性指定在搜索和索引时使用的分析器。默认, Elasticsearch 使用 standard
分析器, 但可以指定一个内置的分析器替代它,例如 whitespace
、 simple
和 english:
{ "man": { "type": "string", "analyzer": "english" } }
但是,可以更新一个映射来添加一个新域,但不能将一个存在的域从 analyzed
改为 not_analyzed
。
空域:
下面三种域被认为是空的,它们将不会被索引:
"null_value": null, "empty_array": [], "array_with_null_value": [ null ]
评分查询与过滤查询:
评分查询:
判断这个文档是否匹配,同时它还需要判断这个文档匹配的有多好(相关性得分)。 此查询的典型用法是用于查找以下文档:
1、查找与 full text search 这个词语最佳匹配的文档
2、包含 run 这个词,也能匹配 runs 、 running 、 jog 或者 sprint
3、包含 quick 、 brown 和 fox 这几个词 — 词之间离的越近,文档相关性越高
4、标有 lucene 、 search 或者 java 标签 — 标签越多,相关性越高
评分查询(scoring queries)不仅仅要找出 匹配的文档,还要计算每个匹配文档的相关性,计算相关性使得它们比不评分查询费力的多。同时,查询结果并不缓存。
过滤查询:
过滤查询是一个“不评分”或者“过滤”查询。即,这个查询只是简单的问一个问题:“这篇文档是否匹配?”。回答也是非常的简单,yes 或者 no ,二者必居其一。
1、created 时间是否在 2013 与 2014 这个区间? 2、status 字段是否包含 published 这个单词? 3、lat_lon 字段表示的位置是否在指定点的 10km 范围内?
过滤查询(Filtering queries)只是简单的检查包含或者排除,这就使得计算起来非常快。考虑到至少有一个过滤查询(filtering query)的结果是 “稀少的”(很少匹配的文档),并且经常使用不评分查询(non-scoring queries),结果会被缓存到内存中以便快速读取,所以有各种各样的手段来优化查询结果