ES中的分词器
全文搜索引擎会用某种算法对要建索引的文档进行分析, 从文档中提取出若干 Token(词元) , 这些算法称为 Tokenizer(分词器) , 这些Token会被进一步处理, 比如转成小写等, 这些处理算法被称为 Token Filter(词元处理器) ,被处理后的结果被称为 Term(词) , 文档中包含了几个这样的Term被称为 Frequency(词频) 。 引擎会建立Term和原文档的Inverted Index(倒排索引), 这样就能根据Term很快到找到源文档了。 文本被Tokenizer处理前可能要做一些预处理, 比如去掉里面的HTML标记, 这些处理的算法被称为 Character Filter(字符过滤器) , 这整个的分析算法被称为 Analyzer(分析器) 。 整个分析过程,如下图所示: 从第一部分内容可以看出:Analyzer(分析器)由Tokenizer(分词器)和Filter(过滤器)组成。 ES允许用户通过配置文件elasticsearch.yml自定义分析器Analyzer,如下: 上面配置信息注册了一个分析器myAnalyzer,在次注册了之后可以在索引或者查询的时候直接使用。该分析器的功能和标准分析器差不多,tokenizer: standard,使用了标准分词器 ;filter: [standard, lowercase, stop],使用了标准过滤器、转小写过滤器和停用词过滤器。 ElasticSearch默认使用的标准分词器在处理中文的时候会把中文单词切分成一个一个的汉字,所以在很多时候我们会发现效果并不符合我们预期,尤其在我们使用中文文本切分之后本该为一个词语却成了单个的汉字,因此这里我们使用效果更佳的中文分词器es-ik。 ik 带有两个分词器: 区别: 下面我们来创建一个索引,使用 ik。创建一个名叫 iktest 的索引,设置它的分析器用 ik ,分词器用 ik_max_word,并创建一个 article 的类型,里面有一个 subject 的字段,指定其使用 ik_max_word 分词器。 批量添加几条数据,这里我指定元数据 _id 方便查看,subject 内容为我随便找的几条新闻的标题 查询 “希拉里和韩国” 这里用了高亮属性 highlight,直接显示到 html 中,被匹配到的字或词将以红色突出显示。若要用过滤搜索,直接将 match 改为 term 即可。
ElastiSearch默认分词器
在Elasticsearch中的数据可以分为两类: 精确值(exact values)以及全文(full text) 。 精确值 :例如日期类型date,若date其有两个值:2014-09-15与2014,那么这两个值不相等。又例如字符串类型foo与Foo不相等。 全文 :通常是人类语言写的文本,例如一段tweet信息、email的内容等。 精确值很容易被索引 :一个值要么相当要么不等。 索引全文值就需要很多功夫。例如我们不仅要想:这个文档符合我们的查询吗?还要想:这个文档有多符合我们的查询?换句话说就是:这个文档跟我们的查询关联大吗?我们很少精确的去匹配整个全文,我们最想要的是去匹配全文文本的内部信息。除此,我们还希望搜索能够理解我们的意图:例如 如果你搜索UK,我们需要包含United Kingdom的文本也会被匹配。 如果你搜索jump,那么包含jumped,jumps,jumping,更甚者leap的文本会被匹配。 为了更方便的进行全文索引,Elasticsearch首先要先分析文本,然后使用分析过的文本去创建倒序索引。 Elasticsearch全文检索默认分词器为standard analyzer。standard analyzer中,character Filter什么也没有做,Token Filters只是把英文大写转化为小写,因此Elasticsearch默认对大小写不敏感,下面主要介绍Tokenizer。 token分隔符把text分隔为token(term)。数据写入的时候会使用standard analyzer处理,text会被处理为token列表。搜索的text也会执行相同的处理,最后使用处理后的token和源text处理后的token匹配。 除了“a-z、A-Z、0-9、_”以外,但不包括“.;,”这三个字符,其他情况都是token分隔符。 “.”链接number和char时,作为token分隔符,其它情况不是分隔符 1)“number.number”经过standard analyzer处理后,token列表[number.number] 例如“123.123s”,搜索“123”是搜索不到的,搜索“123.123s”是可以匹配的 2)“char.char”经过standard analyzer处理后,token列表[char.char] 例如“test.test”,搜索“test”是搜索不到的,搜索“test.test”是可以匹配的 3)“number.char或者char.number”经过standard analyzer处理后,token列表[number、char] 例如“test1.s1”,token列表为[test1、s1],搜索“test1”是可以匹配的 “;”链接number和number时,不作为token分隔符,其它情况都是分隔符 1)“number;number”经过standard analyzer处理后,token列表[number;number] 例如“123;123”,搜索“123”是搜索不到的,搜索“123;123”是可以匹配的 2)“number;char或者char;number”经过standard analyzer处理后,token列表[number、char] 例如“test1;s1”,搜索“test1”是可以匹配的 3)“char;char”经过standard analyzer处理后,token列表[char、char] 例如“test1;ss1”,搜索“test1s”可以匹配的 “,”链接number和number时,不作为token分隔符,其它情况都是分隔符 1)“number,number”经过standard analyzer处理后,token列表[number,number] 例如“123,123”,搜索“123”是搜索不到的,搜索“123,123”是可以匹配的 2)“number,char或者char,number”经过standard analyzer处理后,token列表[number、char] 例如“test1,s1”,搜索“test1”是可以匹配的 3)“char,char”经过standard analyzer处理后,token列表[char、char] 例如“test;s1”,搜索“test”是可以匹配的 在最前面和最后面都是token分隔符 1)“[,.;]char [,.;]”经过standard analyzer处理后,token列表[char] 例如“,.test…”,搜索“test”可以匹配 2)“[,.;]number [,.;]”经过standard analyzer处理后,token列表[number] 例如“,.123…”,搜索“123”可以匹配 3)“_[token分隔符]number或者”经过standard analyzer处理后,token列表[number] 存储字符串:“123 test1:a_b a.b”,分词后的token为:[123、test1、a_b、a.b] 1)使用关键字term搜索 123、test1、a_b或a.b可以匹配 2)使用关键字term搜索“test1##a_b”也可以匹配,在这儿“#”只是起了个分隔符的作用,没有实际意义,和搜索“test1:a_b”的意义一样,搜索字符串分隔为两个token[test1和a_b]去匹配。 3)使用关键字term搜索“test1?.,“也可以匹配,相当于使用token”test1“去搜索 4)搜索“a“,就没有匹配结果,源字符串分隔后的token中没有“a” 存储字符串:“123;456 test”,分词后的term为:[123;456、test] 1) 查询“123”是没有返回结果的 2) 查询“123:456”是没有返回结果的 3) 查询“123;456”是有结果 4) 查询“.123;456#”是有结果 参考: http://unicode.org/reports/tr29/ 除了汉字外的所有字符都是分隔符,每个字都会作为一个term。因此在搜索中,存在除了汉字以为的字符都不起任何作用,不会作为匹配字符.