这里主要测试(text/keyowrd)在(term/match)搜索过程中的区别。
当一个文档被索引时,每个field(字段)都可能创建一个倒排索引,当然,也可以在创建mapping的时候,指定不索引该field。
我们用以下mapping创建索引 test1
PUT test1
{
"mappings": {
"properties": {
"text_col": {
"type": "text"
},
"keyword_col": {
"type": "keyword"
}
}
}
}
如需指定字段不进行索引:
PUT test2
{
"mappings": {
"properties": {
"unindex_col": {
"type": "keyword",
"index": false
}
}
}
}
创建好test1后,写入一条记录,作为后面搜索测试用:
POST /test1/_doc/
{
"text_col": "hello world 你好世界",
"keyword_col": "hello world 你好世界"
}
当写入记录后,在text_col字段上会创建一个倒排索引 ["hello", "world", "你", "好", "世", "界"]
可用如下方式查看默认使用的分词器的分词结果:
GET /_analyze
{
"analyzer": "standard",
"text": "hello world 你好世界"
}
而 keyword_col 不进行分词,使用二进制原样存储为 ["hello world 你好世界"]
当然,也可以不使用默认的分词器,可以指定其它分词器,例:中文分词器。
以下进行查询测试:
1. term 查询 text 字段
term不会分词,比如说要搜索包含 “你好” 这个关键词的记录,会将 “你好” 作为一个整体(关键词)进行搜索。
查询关键词("你好"),查询字段(“text_col”)
1)term不会分词,所以进行搜索的仍为短语"你好";
2)text_col字段在写入记录时,被分词为 ["hello", "world", "你", "好", "世", "界"]进入倒排索引中,并且,顺序是固定的;
此时,短语 "你好" 在text_col字段的倒排索引中无法搜索到记录
GET /test1/_search
{
"query": {
"term" : {
"text_col": "你好"
}
}
}
查询关键词("你"),查询字段(“text_col”)
此时, "你" 在text_col字段的倒排索引中可以命中倒排索引( ["hello", "world", "你", "好", "世", "界"])中的关键词 "你",所以返回该条记录
GET /test1/_search
{
"query": {
"term" : {
"text_col": "你"
}
}
}
2. term 查询 keyword字段
term不会分词,keyword也不会分词,所以他们要两者完全匹配才行。
查询关键词("你好"),查询字段(“keyword_col”)
1) 由于term不分词,所以要进行查询的仍为一个整体 "你好"
2) 由于keyword不分词,所以在keyword_col字段上存储的也为一个整体 "hello world 你好世界"(整个短语未被分词,显然不等于"你好"),由于这两个短语之前并不相等,所以不会被查询出来
GET /test1/_search
{
"query": {
"term" : {
"keyword_col": "你好"
}
}
}
查询关键词("hello world 你好世界"),查询字段(“keyword_col”)
term 和 keyword两者都不分词,当两者完全匹配的时候,是能查出来的:
GET /test1/_search
{
"query": {
"term" : {
"keyword_col": "hello world 你好世界"
}
}
}
3. match 查询 text 字段
match会被分词,所以搜索的时候,要查询的关键词也会被进行分词。
text会被分词,所以写入text字段的记录会被分词后写入到倒排索引中,仅能匹配倒排索引中的分词。
查询关键词("你好")、("您好")、("hell world")、("好你"),查询字段(“text_col”)
1) match分被分词,所以 "你好" 会被分词为 ["你", "好"] 两个关键词进行查询
2) text字段会被分词,所以text_col字段的倒排索引为 ["hello", "world", "你", "好", "世", "界"]
"你" 和 “好” 两个关键词都命中了倒排索引,所以能查出结果:
GET /test1/_search
{
"query": {
"match" : {
"text_col": "你好"
}
}
}
当查询 “您好”时,要查询的关键词 “您好” 被分词为 ["您", "好"],其中 "好" 命中了text_col字段上的倒排索引中的 "好",所以也能查询出结果
GET /test1/_search
{
"query": {
"match" : {
"text_col": "您好"
}
}
}
同样的,当查询 “hell world”时,要查询的关键词 “hell world” 被分词为 ["hell", "world"],其中 "world" 命中了text_col字段上的倒排索引中的 "world",所以也能查询出结果
GET /test1/_search
{
"query": {
"match" : {
"text_col": "hell world"
}
}
}
当查询的关键词为 “好你” 时,同样能返回记录。
GET /test1/_search
{
"query": {
"match" : {
"text_col": "好你"
}
}
}
留意一下score字段的值:
当查询 "你" 的时候,score为 0.2876821
当查询 "hello" 的时候,score为 0.2876821
当查询 "你好" 的时候,score为 0.5753642,命中了两个关键词,score正好翻了一倍
当查询 "好你" 的时候,score仍为 0.5753642
当查询 "你好呀" 的时候,score仍为 0.5753642
当查询 "你好好" 的时候,score仍为 0.8630463,"好" 的score又计算了一次
4. match 查询 keyword字段
match会被分词,所以搜索的时候,要查询的关键词也会被进行分词。
keyword不会被分词,所以keyword_col字段的值 "hello world 你好世界" 作为一个整体被存储。
查询关键词("hello world 你好世界")、("hello world 你好界世")、("你好"),查询字段(“keyword_col”)
当分词按顺序组合起来后与keyword_col字段的值一致的时候,是能查出来的
GET /test1/_search
{
"query": {
"match" : {
"keyword_col": "hello world 你好世界"
}
}
}
当分词的顺序不一致时,无法查询出来:
GET /test1/_search
{
"query": {
"match" : {
"keyword_col": "hello world 你好界世"
}
}
}
当分词只包含短语 "hello world 你好世界" 中的一部分时,无法查询出来:
GET /test1/_search
{
"query": {
"match" : {
"keyword_col": "你好"
}
}
}
小结:
1. term & match
term:精确查询,对查询关键字不进行分词,将要查询的关键字作为一个整体进入要查询的字段上的倒排索引上去匹配
match:模糊查询,对查询关键词先进行分词,然后将分词逐一代入要查询的字段上的倒排索引上去匹配
2. text & keyword
text:对要写入的记录进行分词,然后将分词逐一写入到对应字段上的倒排索引中
keyword:对要写入的记录不进行分词,而是将整个记录作为一个整体写入到对应字段上的倒排索引中