查询API关键字说明
关键字 | 说明 |
---|---|
match | 比如"宝马多少马力"会被分词为"宝马 多少 马力", 所有有关"宝马 多少 马力", 那么所有包含这三个词中的一个或多个的文档就会被搜索出来 |
match_phrase | 一个文档"我的保时捷马力不错"也会被搜索出来,那么想要精确匹配所有同时包含"宝马 多少 马力"的文档就要用match_phrase |
term | 代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇 |
fuzzy | 近似度查询。minimumSimilarity表示是最小相似度,可以通过指定一个相似度来决定模糊匹配的严格程度。默认为0.5,当这个值越小,通过模糊查找出的文档的匹配程度就越低,文档的数量也就越多;当这个值越大,说明要匹配程度更大,匹配的文档数也就越少,当相似度设置为1,那么就退化为TermQuery查询,所以当这个值>=1或<0会抛出IllegalArgumentException异常 |
1.matchAllQuery()
匹配全部文档
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
2.matchQuery(String name,Object text)
匹配单个字段,匹配字段名为filedname,值为value的文档
//单个匹配,搜索name为jack的文档
QueryBuilder queryBuilder = QueryBuilders.matchQuery("name", "jack");
3.matchPhraseQuery(String name, Object text)
匹配单个字段,会拆字
//搜索name中包含有music的文档
QueryBuilder queryBuilder = QueryBuilders. matchPhraseQuery("name", "music");
4.termQuery(String name, String value)
精确匹配,不分词
//搜索name中包含有music的文档
QueryBuilder queryBuilder = QueryBuilders. termQuery("name", "music");
5.multiMatchQuery(Object text, String... fieldNames)
多个字段匹配某一个值
//搜索name中或interest中包含有music的文档(必须与music一致)
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("music",
"name", "interest");
6.termsQuery(String name, String... values)
多词条查询
//Guangzhou、Shaoguan在addr字段中进行查询,只要满足一个就会返回。但是,并不会返回二者的并集。
QueryBuilder query = QueryBuilders.termsQuery("addr", "Guangzhou", "Shaoguan");
7.wildcardQuery(String name, String query)模糊查询
模糊查询,?匹配单个字符,*匹配多个字符
//搜索名字中含有jack文档(name中只要包含jack即可)
WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery("name",
"*jack*");
8.regexpQuery(String name, String regexp)
正则表达式查询
//搜索WC开头的邮政编码
WildcardQueryBuilder queryBuilder = QueryBuilders.regexpQuery("postcode",
"W[0-9].+");
9.prefixQuery(String name, String prefix)
//搜索Bei开头的地址
QueryBuilder query = QueryBuilders.prefixQuery("addr", "Bei");
10.fuzzyQuery(String name, String prefix)
//找出含有华南农业大学或相近地址的数据
QueryBuilder query = QueryBuilders.fuzzyQuery("addr", "华南农业大学");
11.rangeQuery(String name)
// 闭区间
QueryBuilder query = QueryBuilders.rangeQuery("age").from(10).to(20);
// 开区间
QueryBuilder query = QueryBuilders.rangeQuery("age").gt(10).lt(20);
操作篇
索引删除
curl -XDELETE {url}/bom?pretty
索引创建
curl -XPOST {url}/bom?pretty
索引设置settings
curl -XPUT {url}/bom -d '{
"settings": {
"analysis": {
"analyzer": {
"charSplit": {
"type": "custom",
"tokenizer": "ngram_tokenizer"
}
},
"tokenizer": {
"ngram_tokenizer": {
"type": "nGram",
"min_gram": "1",
"max_gram": "1",
"token_chars": [
"letter",
"digit",
"punctuation"
]
}
}
}
}
}'
索引查看settings
curl -XGET {url}/bom/_settings?pretty
索引设置mappings
curl -XPOST {url}/bom/sku/_mappings -d'{
"properties": {
"name": {
"type": "string",
"analyzer": "charSplit"
},
"openid": {
"type": "string",
"analyzer": "charSplit"
},
"specification": {
"type": "string",
"analyzer": "charSplit"
},
"unit": {
"type": "string"
},
"subIds": {
"type": "string"
},
"providerId": {
"type": "string"
},
"skuId": {
"type": "string"
}
}
}'
索引查看mappings
curl -XGET {url}/bom/_mappings?pretty
分词器
标准分词器 Standard Tokenizer
一个标准的分词器提供基于语法的分词器,那是一个适合大部分欧洲语言文档的很好的分词器。分词器实现Unicode文本分割算法,该分割算法在Unicode Standard Annex #29中指定。
参数 | 说明 |
---|---|
max_token_length | 定义最长的分词长度 |
连词分词器 NGram Tokenizer(边际连词分词器 Edge NGram Tokenizer)
如果词的长度大于最短词长度则分词,则依次分成最小长度递进到最大长度的词。
例如:中华人民共和国 min_gram=2,max_gram=3。结果:中华、中华人、华人、华人民、人民、人民共、民共、民共和、共和、共和国、和国。
参数 | 说明 | 默认值 |
---|---|---|
min_gram | 分词后词语的最小长度 | 1 |
max_gram | 分词后词语的最大长度 | 2 |
token_chars | 设置分词的形式,例如,是数字还是文字。elasticsearch将根据分词的形式对文本进行分词。 | - |
参数 | 说明 | 默认值 |
---|---|---|
letter | 单词,字母 a, b, ï or 京 | 1 |
digit | 数字3 or 7 | 2 |
whitespace | 例如 " " or "\n" | - |
punctuation | 例如 ! or " | - |
symbol | 例如 $ or √ | - |
token_chars 所接受的以下形式:
参数 | 说明 | 默认值 |
---|---|---|
letter | 单词,字母 a, b, ï or 京 | 1 |
digit | 数字3 or 7 | 2 |
whitespace | 例如 " " or "\n" | - |
punctuation | 例如 ! or " | - |
symbol | 例如 $ or √ | - |
关键字分词器 Keyword Tokenizer
参数 | 说明 | 默认值 |
---|---|---|
buffer_size | 关键字的长度 | 256 |
keyword分词器输出和它接收到的相同的字符串。即不分词
参数 | 说明 | 默认值 |
---|---|---|
buffer_size | 关键字的长度 | 256 |
字符分词器 Letter Tokenizer
字符(letter)类型分词器将文本按非字符(non-lentter)进行分词。这就是说,它定义临近的最大长度的字符为一个词。注意,这个适合大部分欧洲的语言,但是对一些亚洲的语言来说就很糟糕了,它们的词不是以空格来分割的。
小写分词器 Lowercase Tokenizer
lowercase将词全部转换成小写,其他的同letter Tokenizer
空格分词器Whitespace Tokenizer
以空格来分词
模式分词器/正则分词器 Pattern Tokenizer
参数 | 说明 | 默认值 |
---|---|---|
pattern | 正则表达式的pattern,默认是 \W+. | |
flags | 正则表达式的 flags. | |
group | 哪个group去抽取数据。 默认是 to -1 (split). |
根据正则表达式的匹配规则来分词。
参数 | 说明 | 默认值 |
---|---|---|
pattern | 正则表达式的pattern,默认是 \W+. | |
flags | 正则表达式的 flags. | |
group | 哪个group去抽取数据。 默认是 to -1 (split). |
标准Email URL分词器 UAX Email URL Tokenizer
和标准分词器一样,但是把email和url当作一个词。
UAX Email URL Tokenizer有人翻译为'不拆分email、url的分词器',觉得不太恰当,UAX个人认为是Unicode Standard Annex,见标准分词器中。
路径层次分词器 Path Hierarchy Tokenizer
例如:/something/something/else
结果:/something、/something/something、/something/something/else
默认定界符: /
典型的编译器 Classic Tokenizer
classic分词器提供基于语法的分词器,这对英语文档是一个很好的分词器。
Thai Tokenizer
对泰文进行分词,如果用在其他语言上同标准分词器。
IK中文分词器
创建索引
curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
{
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}'
配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>
热更新 IK 分词使用方法
目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">location</entry>
其中 location 是指一个 url,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。
该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。
该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。
满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。
分词过滤器
standard
将字符串分割成单独的字词
lowercase
标记过滤器,将所有标记转换为小写。
stop
标记过滤器,删除所有可能会造成搜索歧义的停用词,如 a,the,and,is。
html_strip
删除所有的 HTML 标签,并且将 HTML 实体转换成对应的 Unicode 字符,比如将 Á 转成 Á。
stemmer
将单词转化为他们的根形态(root form)
ascii_folding
删除变音符号,比如从 très 转为 tres。
自定义分析器
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": { ... custom character filters ... },
"tokenizer": { ... custom tokenizers ... },
"filter": { ... custom token filters ... },
"analyzer": { ... custom analyzers ... }
}
}
}
作为例子,我们来配置一个这样的分析器:
用 html_strip 字符过滤器去除所有的 HTML 标签
将 & 替换成 and,使用一个自定义的 mapping 字符过滤器
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}
}
- 使用 standard 分词器分割单词
- 使用 lowercase 标记过滤器将词转为小写
- 用 stop 标记过滤器去除一些自定义停用词。
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [ "the", "a" ]
}
}
根据以上描述来将预定义好的分词器和过滤器组合成我们的分析器:
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}
}
用下面的方式可以将以上请求合并成一条:
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [ "the", "a" ]
}},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}}
}}}
原理
倒排索引(inverted index)
例如,我们有两个文档,每个文档content字段包含:
1. The quick brown fox jumped over the lazy dog
2. Quick brown foxes leap over lazy dogs in summer
为了创建倒排索引,我们首先切分每个文档的content字段为单独的单词
Term | Doc_1 | Doc_2 |
---|---|---|
Quick | X | |
The | X | |
brown | X | X |
dog | X | |
dogs | X | |
fox | X | |
foxes | X | |
in | X | |
jumped | X | |
lazy | X | |
leap | X | |
over | X | X |
quick | X | |
summer | X | |
the | X |
现在,如果我们想搜索"quick brown",我们只需要找到每个词在哪个文档中出现即可:
Term | Doc_1 | Doc_2 |
---|---|---|
brown | X | X |
quick | X | |
----- | ------- | ----- |
Total | 2 | 1 |
两个文档都匹配,但是第一个比第二个有更多的匹配项。 如果我们加入简单的相似度算法(similarity algorithm),计算匹配单词的数目,这样我们就可以说第一个文档比第二个匹配度更高——对于我们的查询具有更多相关性。
但是在我们的倒排索引中还有些问题:
- "Quick"和"quick"被认为是不同的单词,但是用户可能认为它们是相同的。
- "fox"和"foxes"很相似,就像"dog"和"dogs"——它们都是同根词。
- "jumped"和"leap"不是同根词,但意思相似——它们是同义词。
上面的索引中,搜索"+Quick +fox"不会匹配任何文档(记住,前缀+表示单词必须匹配到)。只有"Quick"和"fox"都在同一文档中才可以匹配查询,但是第一个文档包含"quick fox"且第二个文档包含"Quick foxes"。
用户可以合理地希望两个文档都能匹配查询,我们也可以做得更好。
如果我们将词为统一为标准格式,这样就可以找到不是确切匹配查询,但是足以相似从而可以关联的文档。例如:
- "Quick"可以转为小写成为"quick"。
使用大小写过滤器
- "foxes"可以被转为根形式"fox"。同理"dogs"可以被转为"dog"。
使用分词器
- "jumped"和"leap"同义就可以只索引为单个词"jump"
使用词汇单元过滤器
Term | Doc_1 | Doc_2 |
---|---|---|
brown | X | X |
dog | X | X |
fox | X | X |
in | X | |
jump | X | X |
lazy | X | X |
over | X | X |
quick | X | X |
summer | X | |
the | X | X |
但我们还未成功。我们的搜索"+Quick +fox"依旧失败,因为"Quick"的确切值已经不在索引里,不过,如果我们使用相同的标准化规则处理查询字符串的content字段,查询将变成"+quick +fox",这样就可以匹配到两个文档。