Elasticsearch分析与检索
Posted 融极
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch分析与检索相关的知识,希望对你有一定的参考价值。
概述
虽然通过文档_id可以获取到文档,但是_id字段一般都是一个无意义的值,在实际应用中更多是使用文档其他有意义字段做检索。Elasticsearch提供了一个专门用于检索的_search接口,这个接口可以根据指定的查询条件检索文档,Elasticsearch强大的检索能力都体现在这个接口的应用上。除了本章介绍的文档检索基于_search接口,之后介绍的聚集查询也是基于这个接口,只是使用的参数及格式不同而已。
Elasticsearch可以用于文档检索的接口除了_search以外,还包括_count、_msearch、_scripts等。此外,还有一组辅助文档检索的接口可供使用。它们可以查看检索执行情况,为性能调优提供依据,包括_validate、_explain、_field_caps、_search_shards等。
_search接口
_search接口可以使用 GET或者POST方法请求,在请求路径中可以指定一个或多个索引,还可以使用_all或者星号"*"匹配所有索引。如果不指定索引名称,实际上也是匹配所有索引。Elasticsearch为使用这个接口定义了一种查询语言——DSL(Domain Specific Language)。DSL是一套基于JSON的查询语言,这种只在某一领域使用的语言通常称为领域特定语言,而它们英文单词首字母简写就是DSL。本书后续章节都将简称这种语言为DSL,由于DSL内容非常庞杂,将在本书第5章单独介绍。
_search接口有两种请求方式,一种是基于URI的请求方式,另一种则是基于请求体的请求方式。无论是哪一种,它们执行的语法根基都是DSL,只是在使用形式上不同而已。
基于URI
GET /kibana_sample_data_logs/_search?q=message:firefox chrome
POST _search
GET _search
_search接口基于URI的请求方式比较简单,DSL查询条件以请求参数q传递给接口。使用_search接口的最简单形式就是不挂任何参数直接调用,可以在路径中添加索引名称,也可以不添加。
第一请求中参数q定义的内容叫查询字符串(Query String),它的含义是检索message字段值中包含firefox或chrome的文档。查询字符串不仅可以在基于URI的检索中使用,也可以在基于请求体的检索中使用,是DSL定义的一种检索方法。查询字符串属于全文检索,这意味着查询字符串在检索前会被分析器解析为一系列词项和运算符。上面示例中"firefox chrome"会被解析为chrome和firefox两个词项,然后在与message字段的此项索引做匹配。只要message字段中包含firefox或chrome,这个文档就满足查询条件。
查询字符串
查询字符串的基本格式“<字段名>:<查询值>”,其中字段名可以指定,也可以不指定。如果没有指定字段名,要匹配的字段由index.query.default_field参数设置。这个参数的默认值是*.*,即索引字段中查询。此外,还可以使用参数df(Default Field)指定要查询的字段名,它与参数q一样是可以用在URI中的参数。如果指定了字段名,查询将在指定字段中匹配词项。除了直接指定字段名以外,还可使用通配符等形式匹配字段,例如:4-2 特殊格式的字段名
GET kibana_sample_data_logs/_search?q=geo.\\*:CN US
GET kibana_sample_data_logs/_search?q=_exists_:geo
在示例4-2中,查询字符串"geo.*:CN US"将在geo的子字段中匹配CN或US。第二个查询字符串中的_exists_不是一个具体的字段名,而是代表所有非空的title字段。
下面再来看看查询字符串中的查询值。查询值会在检索前通过分析器拆分为词项,在检索时只要字段中包含任意一个词项就视为满足条件。在实现上,这其实是使用了DSL语言中的match查询。如果使用双引号将它们括起来,_search接口将使用DSL的match_phase做短语匹配。从效果上看就类似于整个短语做检索,而不是使用单个词项做检索。查询值除了包含词项本身以外,还可以包含操作费OR或AND,注意它们必须大写否则将失败为词项。例如,"(tom smit) AND jhon"代表的含义是同时包含tom、jhon或者smith、jhon的字段。除了可以包含词项、操作符以外,查询字符串的查询值中还可以包含通配符正则表达式等。如下4-1给出的一些可能的用法。
请求参数
基于URI调用_search接口时可以使用的参数,除了前述的q和df以外还有很多。例如,_source参数可以用来设置在返回结果中是否包含_source字段,还可以使用_source_include或_source_exclude参数包含或排除源文档的字段。这样的参数还有很多,它们大多数与基于请求体的参数具有相同的名称和含义。不仅如此,部分参数对于其他接口也可使用,所以对于参数的介绍将在本章4.2节统一讲解。表4-2先将这些参数总结出来供参考:
例如:
GET kibana_sample_data_logs/_search?q=_exists_:geo&_source
基于请求体
基本请求体的接口调用,可以在请求体重传递DSL检索条件。尽管可以GET或POST方法请求_search接口,但由于一些客户端不支持使用GET方法发送请求体,所以最好使用POST方法请求基于请求体的_search接口。使用请求体检索时,DSL检索条件通过请求体的query参数设置。例如检索目的地为中国的航班。示例:4-3 基于请求体的查询
POST kibana_sample_data_flights/_search
"query":
"term":
"DestCountry":"CN"
在示例4-3的检索中,采用了DSL基于词项(term)的查询,检索条件是DestCountry为CN。DSL中最简单的查询关键字是match_all和match_none,它们分别代表匹配所有、都不匹配,例如:4-4
POST kibana_sample_data_logs/_search
"query":
"match_all":
POST kibana_sample_data_flights/_search
"query":
"match_none":
除了这两种查询以外,DSL还定义了多种多样的查询语法。在请求体中可以使用的参数除了query以外还有很多,它们很多与表4-2中的URI参数名称和含义都是相同的。
分页与排序
在查询大量数据时必须要做分页,一方面是便于用户浏览,但更重要的是防止一次加载数据量过大而导致内存溢出。_search接口提供了一组参数可用于检索结果分页,但它们有各自不同的应用场景,需要区别对待。
from/size分页参数
_search接口提供的from和size两个参数可以实现分页,其中from参数代表检索文档的起始位置,默认值为0;而size参数则代表每次检索文档的总量,默认值为10。form和size即可以在URI参数中使用,也可以在请求体中使用。例如示例4-5中的两个请求都是从第100条文档开始,一共取20条文档:示例4-5
from与size的和不能超过index.max_result_window这个索引配置项设置的值。默认情况下这个配置项的值为10000,所以如果要查询10000条以后的文档,就必须要增加这个配置值。例如,要检索第10000条开始的200条数据,这个参数的值必须要大于10200,否则将会抛出类似“Result window is too large”的异常。由此可见,Elasticsearch在使用from和size处理分页问题时会将所有数据全部取出来,然后再截取用户指定范围的数据返回。所以在查询非常靠后的数据时,即使使用了from和size定义的分页机制依然有内存溢出的可能,而index.max_result_window设置的10000条则是对Elasticsearch的一种保护机制。
那么Elasticsearch为什么要这么设计呢?首先,在互联网时代的数据检索应该通过相似度算法,提高检索结果与用户期望的附和度,而不应该让用户在检索结果中自己挑选满意的数据。以互联网搜索为例,用户在浏览搜索结果时很少会看到第3页以后的内容。假如用户在翻到第10000条数据时还没有找到需要的结果,那么他对这个搜索引擎一定会非常失望。其次,如果真的需要遍历所有数据,不能单纯使用from和size,应该结合scroll接口使用。
scroll参数
scroll即是_search接口的参数也是接口,它提供了一种类似数据库游标的文档遍历机制,一般用于非实时性的海量文档处理需求。例如,将一个索引中的文档导入到另一个索引中,或者将索引中的文档导入到mysql中。使用scroll机制有两个步骤,第一步是创建游标,第二步则是对游标遍历。这两个步骤基于_search接口执行,例如:4-6创建游标
其中,scroll参数只能在URI中使用,而不能出现在请求体中。它定义了检索生成的游标需要保留多长时间,比如2m代表2分钟,1h代表1小时。scroll保留时长不是处理完所有数据所需要的时长,而是处理单次遍历所需要的时间。从性能角度来看,保留时间越短,空间利用率就越高,所以应该根据单次处理能力设置这个值。size参数可以放在请求体中,也可以挂在地址后面,代表了每次遍历时返回的文档数量。size只能在初始查询时指定在遍历时不能更改,请求体中还可以包含其他_search接口的合法参数。在添加了scroll参数后,返回的结果中将包含一个名为_scroll_id的字段,它惟一地代表了一个scroll查询的结果。接下来,根据这个_scroll_id就可以对结果进行遍历了。
例如:4-7 遍历游标
在遍历游标时,不需要指明索引或映射类型,反复调用_search/scroll接口就可实现对结果的遍历了。请求体中的scroll参数相当于延长了游标的存活时长,而scroll_id则是在初始查询时返回的_scroll_id值。在遍历过程中将根据初始查询时设置的size值返回相应数量的文档,但在遍历过程中不能重新修改size值。每次调用scroll都会自动向后遍历,直到所有文档全部遍历结束。在遍历过程中,每次返回的结果中还是会包含_scroll_id字段,通常来说它的值会保持不变。
scroll在超时后将自动删除,但Elasticsearch也为用户提供了主动删除scroll的接口。可以通过请求体发送要删除的游标,例如:
对于海量文档的遍历,Elasticsearch还支持对scroll再做片段分割,每一个分割后的片段又可以被独立使用。例如:4-9游标分段
其中,max定义了分割片段的总量为2,而id则定义了当前请求返回哪一个片段。所以,上面的请求将会把游标分为两个片段,当前请求返回第一个片段。id值从0开始,所以它的值应该小于max。在返回的结果中,同样也会包含_scroll_id字段。每一个游标片段都是独立的,可以使用多线程并发处理。从物理角度来看,Elasticsearch会让游标片段分配到不同的索引分片上以提升遍历速度。所以,游标片段数量不应该大于索引分片数量,否则游标分段的性能将受到影响。正因如此,游标片段数量也有上限,默认为1024,由index.max_slices_per_scroll参数设置。
search_after参数
在前面介绍分页时提到了两种机制,一种是使用from/size,一种是使用scroll。这两种机制都会将数据整体加载进来,不同的是from/size机制下每一次请求都会加载,而scroll则只在初始时加载。所以,scroll实际上比较适合对同一结果集做多次迭代,但在数据量比较大时依然对性能有影响。为此,Elasticsearch提供了另外一种机制search after,它使用search_after参数定义检索应该在文档某些字段的值之后查询其他文档,所以需要预先以这些字段排序。例如:4-10 search_after
在上面的请求中,kibana_sample_data_flights将按DestCountry和FlightNum字段排序,但只返回DestCountry为AE并且FlightNum为AR9OTDM之后的10条文档(size默认为10)。所以这种机制本质上是通过匹配字段,动态决定第一条文档是哪一个,所以在这种情况下from必须设置为0或-1。不仅如此,参与排序的字段值需要保证惟一。虽然这种惟一性保证并非必须,但如果不惟一则在查询时将导致歧义,有可能返回不正确的结果。
需要特别注意的是,这种机制在匹配字段时并非使用精确匹配,而是只要部分满足即可。在上面的例子中,如果含有一个FlightNum为AR9OTDMXXX,也是满足匹配条件的。但由于AR9OTDMXXX会排在AR9OTDM之后,所以还是不会出现问题的。
排序后的检索结果中,都会在最后附带一个排序字段的值,例如示例4-10检索结果最后会包含如下内容:
4-11排序结果
这个内容正好与当前检索结果中的DestCountry和FlightNum字段值相同,可以为下一次search after使用。讲到这里就涉及到检索的另外一个重要内容-排序。
sort参数
排序是文档检索中另一个重要的话题,在很多应用中排序都是一个必不可少的功能。例如,按商品售价、销量排序以搜索出物美价廉的商品。例如在示例4-10中,由于使用search after机制已经使用到了排序。Elasticsearch提供的排序可以依照文档一个或多个字段排序,包括两个虚拟字段_score和_doc。按_score排序就是按文档相似度得分排序,而_doc则是按索引次序排序。例如:4-12排序
在示例4-12中给出了几种排序方法,将会依次按AvgTicketPrice、FlightDelayMin字段升序排列,再按DistanceKilometers、_score字段降序排列。排序执行的顺序与它们在sort数组中的次序一致。与SQL语言类似,asc代表升序,desc代表降序。默认情况下,除_score按降序排列,其余字段都按升序排列。Elasticsearch支持使用数组类型或多值类型字段做排序,但需要定义如何使用数组中的数据。这包括min、max、avg、sum、median等几种情况,分别代表取最小值、最大值、平均值、总和或中值参与排序,可通过参数mode来定义。例如在下面的示例中,将按products.base_price字段的最大值做降序排列:4-13数组排序
默认情况下,查询结果会按_score字段降序排列,_score字段是文档与查询条件的相似度得分。也就是说,越是靠前的结果与查询条件的相似度越高,这与人们的使用习惯相符。相似度问题在全文检索中是一个非常重要的话题,将在本书第6章中专门讨论。
此外,由于排序算法需要知道所有参与排序的值才可能做运算,所以参与排序字段在文档中的值都需要加载到内存中来。这一方面对节点分配的内存提出了更高要求,另一方面也要求参与排序的字段必须支持文档值(Doc Value)或fielddata机制。这是因为倒排索引保存的是词项到文档的对应关系,适用于通过词项检索文档。但在排序时需要的是通过文档找到字段值参与排序,所以必须保证能够通过文档找到字段值。在默认情况下,文档值机制对于非text类型的字段都是开启的,而text类型则只能通过开启fielddata机制才可能支持排序。
字段投影
投影(Projection)的概念源于关系型数据库,是指从一个关系中选取若干个属性形成一个新的关系。简单来说,就是在查询表时不将所有字段返回,而只返回其中的部分字段。Elasticsearch并没有直接引入投影的概念,但支持类似投影的操作。这主要体现在对查询结果的_source字段和fields字段的定制上。
_source参数
Elasticsearch文档查询结果中会包含_source元字段,这个字段存储了文档的最原始数据。_search接口提供了_source参数,可以定制源文档中哪些字段出现中_source中。这个参数可以在URI中使用,也可以在请求体中使用。例如在示例4-14中,_source将只包含DestCountry字段的值:4-14 _source参数
POST kibana_sample_data_flights/_search
"_source": "DestCountry",
"query":
"match_all":
如果需要返回多个字段,可以使用数组设置_source,并且可以使用通配符星号“*”。例如下面两个请求,都将返回OrigiOriginCountry和DestCountry字段:4-15使用数组和星号
POST kibana_sample_data_flights/_search
"_source": ["OriginCountry","DestCountry"]
POST kibana_sample_data_flights/_search
"_source": "*Country"
当然,使用星号匹配的范围更大一些,如果索引中包含其他以Country结尾的字段,它们也将出现在返回结果中。类似地,_source也可以设置为false,这将禁止在返回的结果中包含_source源文档内容,而只包含元字段。除此之外,还可以在_source字段中添加includes和excludes字段,以明确包含和排除字段。例如在示例4-16中,将所有包含lon、lat等经纬度信息的字段包含进来,而又排除了DestLocation的子字段,所以在返回的结果中应该只包含OriginLocation:
POST kibana_sample_data_flights/_search
"_source":
"includes":["*.lon","*.lat"],
"excludes": "DestLocation.*"
stored_fields参数
除了使用_source字段过滤可以出现在源文档中的字段以外,还可以使用stored_fields字段指定哪些被存储的字段出现在结果中。当然这些字段的store属性要设置为true,否则即使在stored_fields中设置了它们,也会被忽略。例如,在示例4-17中,author字段的store参数为true而title设置为false,则在查询的结果中将忽略title:
在返回结果中会增加一个fields字段,其中包含了stored_fields中配置的字段值。此外,在使用stored_fields之后,_source字段默认将不会出现在结果中,但可通过将_source参数设置为true让它返回。字段的store参数在本书第2章2.2.2节也有过介绍,当文档某字段单独使用的频率比较高而其他字段值占用空间又非常大时,就可以把这种常用的字段单独保存起来使用。
docvalue_fields参数
docvalue_fields也是_search接口的参数,它用于将文档字段以文档值机制保存的值返回。文档值机制是非text类型字段支持的一种在硬盘中保存字段原始值的机制,可通过字段的doc_value参数设置开启或关闭。4-18 docvalue_fields
在示例4-18中,docvalue_fields接收的对象有两个属性,field定义字段名称,而format则定义数值和日期的格式。在示例中使用了日期格式epoch_millis,所以返回结果将以毫秒数显示timestamp字段。format可以使用use_field_mapping关键字,它代表的含义是使用字段在索引映射中定义的格式。类似于stored_fields,docvalue_fields查询的返回结果中也会增加一个fields字段,其中包含了在docvalue_fields中声明的字段及其文档值。与stored_fields不同的是,docvalue_fields的返回结果中默认会包含_source字段。所以在示例4-18中使用_source参数过滤了返回结果以保证_source中也只包含timestamp字段。
script_fields参数
script_fields同样是_search接口的参数,它可以通过脚本向检索结果中添加字段。与stored_fields和docvalue_fileds类似,通过脚本添加的字段也会出现在结果的fields字段中。默认情况下,使用了script_fields参数后,_source字段也不会出现在返回结果中,但可使用_source参数配置开启。例如在示例4-19中向返回结果添加了price_per_km字段,它通过AvgTicketPrice字段和DistanceKilometers字段相除而得,反映了机票每公里的平均票价:
script_fields中默认使用的脚本也是Painless,可以在这个上下文中使用的变量见表4-3。
分析器与规整器
在Elasticsearch中,文档编入索引时会从全文数据中提取词项,这个过程被称为文档分析(Analysis)。文档分析不仅存在于文档索引时,也存在于文档检索时。文档分析会从查询条件的全文数据中提取词项,然后再根据这些词项检索文档。文档分析器(Analyzer)是Elasticsearch中用于文档分析的组件,通常由字符过滤器(Character Filter)、分词器(Tokenizer)和分词过滤器(Token Filter)三部分组成。它们就像是连接在一起的管道,共同完成对全文数据的词项提取工作。如图4-1所示。
字符过滤器读入最原始的全文数据,并对全文数据中的字符做预处理,比如从html文档中将类似<b>这样的标签删除。字符过滤器可以根据实际情况添加,可以没有也可以有多个。分词器接收由字符过滤器处理完的全文数据,然后将它们根据一定的规则拆分成词项。英文分词规则比较简单,直接使用空格分隔单词即可;但中文分词规则比较复杂,需要根据词意做分词且需要字典支持。对于一个分析器来说,分词器是必不可少的,而且只能有一个。在使用分析器时,可以根据文档内容更换分词器,比如对于中文来说需要将分析器的分词器更换为中文分词器。最后,分词过滤器的职责是接收由分词器提取出来的所有词项,然后对这些分词做规范化处理,比如将分词转换为小写、去除“的、地、得”等停止词(Stop Word)。分词过滤器与字符过滤器一样,可以根据需要添加和配置,可以没有也可以有多个。
除了分析器以外,Elasticsearch还提供了一种称为规整器(Normalizer)的文档标准化工具。规整器与分析器的最大区别在于规整器没有分词器,而只有字符过滤器和分词过滤器,所以它能保证分析后的结果只有一个分词。文档规整器只能应用于字段类型为keyword的字段,可通过字段的normalizer参数配置字段规整器。规整器的作用就是对keyword字段做标准化处理,比如将字段值转为小写字母等等。规整器与分析器共享相同的字符过滤器和词项过滤器,但规整器只能使用那些结果只有一个词项的过滤器。
设置分析器
由于文档分析通过分析器完成词项提取,所以想要影响文档索引和文档检索时的词项提取,就要修改它们使用的分析器。对于所有text类型的字段,都可以在创建索引时为它们指定分析器。对于非text类型字段来说,由于本身不存在全文本数据词项提取的问题,所以也就没有设置分析器的问题。例如,在示例4-20中,title字段在文档编入索引时使用standard分析器,而通过title字段检索文档时则使用simple分析器:
在创建索引时如果没有指定分析器,Elasticsearch会查找名为default的分析器,如果没有则使用standard分析器。文档检索时使用的分析器有一点复杂,它依次从如下参数中查找文档分析器,如果都没有设置则使用standard分析器:
1)检索请求的analyzer参数;
2)索引映射字段的search_analyzer参数;
3)索引映射字段的analyzer参数;
4)索引配置中的default_search参数。
以示例4-20中的articles索引为例,尽管设置的检索分析器为simple,但如果在检索文档时使用analyzer参数设置为english分析器,最终使用的分析器依然是english分析器。如第4.1节所述,analyzer参数可以作为_search接口的URI参数也可以出现的请求体中,例如:
_analyze接口
Elasticsearch提供了一个_analyze接口,可以用于查看分析器处理结果,这在学习分析器时非常有帮助。由于_analyze接口仅用于查看分析器功能,所以在发送请求时不需要指定索引,虽然在指定索引时也不会报错。例如示例4-22就是用standard分析器处理文本:
_analyze接口可以使用POST发送请求,也可以使用GET发送请求。返回的结果中,将包含所有提取出来的词项以及它们的位置、偏移量等信息:
其中,token是提取出来的词项,start_offset与end_offset是词项在整个文本中的起始位置和终止位置(即偏移量),position是词项在所有词项中的次序,而type则是词项的类型(与词项本身和分析器相关)。如果要查看分词中更详细的内容,可以在请求体中将explain参数设置为true。
实际上除了analyzer参数以外,还可以使用tokenizer、filter、char_filter的组合来测试分词器、分词过滤器、字符过滤器的功能。
_termvectors接口
内置分析器与中文分析器
Elasticsearch内置了很多分析器,这些分析器以名称标识,不需要做太多的配置就可以直接使用。比如前面提到的standard、simple、english等都是内置分析器,这些分析器可直接使用,或者通过配置生成自定义的分析器再使用。新分析器需要在创建索引时定义,例如:
在示例4-27中,创建了一个索引analyzer_test,并定义了一个名为my_analyzer的分析器。该分析器基于standard分析器,但将词项最大长度设置为5,并定义了一组停止词。它们通过max_token_length和stopwords参数设置,有关它们的说明请参考下面standard分析器的介绍。完成了分析器的定义后,就可以在_analyzer接口中使用了:
由于定义了停止词,在示例4-28中分析的文档this和is这两个词项会从最终结果中剔除;而elasticsearch、logstash和kibana这三个词项,由于长度超过5将被拆分为多个词项。在定制分析器使用的type参数指定了基于哪种分析器做定制,但并不是每一种分析器都可以定制。每一种可定制的分析器在定制时又有自己可用的参数,这些参数将在介绍具体分析器时讲解。
standard分析器
standard分析器是默认分析器,它使用标准分词器(Standard Tokenizer,standard)提取词项。标准分词器提取词项的规则是根据Unicode文本分隔规范中定义的标准分隔符区分词项,可以在官网“http://unicode.org/reports/tr29/”中可以查看完整定义。比较常见的分隔符包括空格、换行、标点符号、数学运算符等等,主要针对类似英文这种拼写类语言。standard分析器没有字符过滤器,但包含了三个词项过滤器。它们分别是
● 标准词项过滤器(Standard Token Filter):只是占位,实际没做任何处理;
● 小写字母过滤器(Low Case Token Filter):作用是将词项转换成小写字母;
● 停止词过滤器(Stop Token Filter):将停止词删除,默认关闭。
所以在默认情况下,standard分析器的实际分词效果是使用Unicode文本分隔规范提取词项并全部转换为小写。standard分析器是可配置分析器,可使用配置参数见表4-4。
stop分析器
stop分析器使用小写字母分词器(Lowercase Tokenizer,lowercase),分词规则是使用所有非字母分隔单词,并且会将提取出来的词项转换为小写。所以使用stop分析器提取出来的词项一定不会包含数字、空格、标点符号等特殊字符。stop分析器没有字符过滤器,但包含一个停止词过滤器。这个过滤器与standard中的停止词过滤器是相同的,只是它的默认值为_english_而不是_none_。停止词过滤器针对每一种语言内置了一组停止词,它们包含了每种语言中常见的停止词。这些内置的停止词如下:
arabic,armenian,basque,bengali,brazilian,bulgarian,catalan,czech,danish,dutch,english,finnish,french,galician,german,greek,hindi,hungarian,indonesian,irish,italian,latvian,norwegian,persian,portuguese,romanian,russian,sorani,spanish,swedish,thai,turkish
停止词除了可以使用上述内置停止词以外,还可以通过stopwords参数使用数组定义停止词全集,或者通过stopwords_path参数指定停止词文件路径。停止词文件是定义停止词全集的另一种方式,它的基本格式是每行定义一个停止词,所以可以按行将所有停止词声明在文件中。
所以stop分析器在使用上的实际效果就就是以非字母分隔单词,并且在词项结果中去除所有英文停止词。stop分析器也是一种可配置的分析器,可使用配置参数见表4-5。
pattern分析器
pattern分析器使用模式分词器(Pattern Tokenizer,pattern),该分词器使用Java正则表达式匹配文本以提取词项,默认使用的正则表达式为“\\W+”,即以非字母非数字作为分隔符。pattern分析器没有字符过滤器,但包含两个过滤器——小写字母过滤器和停止词过滤器。这两个过滤器与standard分析器中的过滤器完全一样,所以pattern分析器默认提取出来的词项也会被转换为小写并且不包含停止词。
pattern分析器是可配置分析器,参数主要是设置正则表达式和停止词,见表4-6。
custom分析器
custom分析器可以理解为一个虚拟的分析器,不能直接使用。但custom分析器是一个可配置的分析器,一个专门用于自定义的分析器,在custom基础上配置出来的自定义分析器是可以使用的。前述几个可配置的分析器虽然也可配置,但不能在配置中替换字符过滤器、分词器和分词过滤器。而custom分析器的配置参数中包含char_filter、tokenizer、filter三个参数,可以通过它们定义需要使用的字符过滤器、分词器和分词过滤器。由于分词器是分析器必要的组件,所以在配置custom分析器时tokenizer参数是必选项。custom分析器可用配置参数见表4-7。
Elasticsearch内置提供了十多种分词器、几十种分词过滤器,但常用的几种在前述分析器介绍中已经见过。对于其他分词器和分词过滤器,因为它们并不常用,也限于篇幅,本节就不展开介绍了,读者可到Elasticsearch官方网站找到相关资料。
其他内置分析器
前述几个分析器都是可以配置的分析器,下面再来看几个不可配置的分析器simple、whitespace和keyword。它们不仅不可配置,而且都没有字符过滤器和词项过滤器。
simple分析器与stop分析器一样使用小写字母分词器(Lowercase Tokenizer,lowercase),所以提取出来的分词与stop分析器相同。只是simple分析器没有过滤器,所以不能做停词处理。whitespace分析器使用空格作为词项分隔符,提取出来的词项不做大小写转换,使用的分词器是空格分词器(Whitespace Tokenizer,whitespace)。keyword分析器是一个不做任何处理的分析器,它会将文档内容整体作为一个词项返回,使用的分词器是关键字分词器(Keyword Tokenizer,keyword)。
除了以上分析器,Elasticsearch还提供了一组与语言相关的分析器,用于处理各种语言内容的文档。这组分析器有30多种,支持世界上大多数语言。其中可以用来处理中文的分析器为cjk,cjk是China、Japan和Korea三个单词的简写,代表以东亚国家为主的象形文字。但cjk在处理中文时并不好用,它会把每个汉字都提取为词项,所以意义不大。
中文分析器
中文分析器中比较有名就是IK,包括ik_smart、ik_max_word两种。这两者的区别在于它们提取词项的粒度上,前者提取粒度最粗,而后者则最细。比如“中文分析器”使用ik_smart只会提取出“中文”和“分析器”两个词项,而使用ik_max_word则会提取出“中文”“分析器”“分析”和“器”四个词项。也就是说,ik_max_word会从文本中穷尽所有可能的词语组合,所以它提取出来的词项会远多于ik_smart。
Elasticsearch默认并不支持IK,所以在使用IK前需要以插件的形式将它安装到Elasticsearch中。安装IK插件可以直接将插件解压缩到Elasticsearch的plugins目录中,也可以通过elasticsearch-plugin命令完成安装。先到IK在github上的地址,选择合适的版本下载安装包,IK版本必须要与Elasticsearch版本严格一致,否则在启动Elasticsearch时会报错。IK下载地址为“https://github.com/medcl/elasticsearch-analysis-ik/releases”。
如果采用直接解压缩的方式安装IK,需要在Elasticsearch的安装路径下找到plugins目录,并在这个目录创建一个新文件夹并命名为ik,然后将安装包直接解压缩到这个目录。IK插件安装的目录名称并非一定要叫ik,只要这个目录在plugins路径下即可。如果使用elasticsearch-plugin命令安装IK就更简单了,这个命令位于Elasticsearch安装目录下的bin目录中。直接进入命令行,键入如下命令:4-29安装IK
示例4-29展示的是一条完整的命令,elasticsearch-plugin insall后接的是IK下载地址,将路径中的/v7.0.0和文件名中的7.0.0替换成需要的版本号即可。键入回车后,elasticsearch-plugin会到指定的路径下载IK,并将它安装到plugins路径中的analysis-ik目录中。无论以哪种方式安装IK,安装结束后都需要重新启动Elasticsearch。接下来就可以体验一下IK分析器了,如示例4-30所示:
中文分析及IK分析器是一个很大的话题,本书限于篇幅不太可能面面俱到。有关IK分析器的更多介绍请参考官网,地址为“https://github.com/medcl/elasticsearch-analysis-ik”。
其他检索接口
前面几个小节实际上都是围绕着_search接口,但实际上Elasticsearch还提供了许多与文档检索有关的接口。比如,如果想要查看索引中满足条件的文档数量可以使用_count接口,如果想要执行一组检索可以使用_msearch接口,而_scripts接口则提供了一种定义查询模板的方法。本节就来看看这些接口。
_count接口
_msearch接口
辅助接口
_validate接口
_explain接口
_field_caps接口
_search_shards接口
以上是关于Elasticsearch分析与检索的主要内容,如果未能解决你的问题,请参考以下文章