Elasticsearch进阶笔记第三十七篇

875 阅读5分钟

Elasticsearch高手进阶篇(76)

elasticsearch高手进阶_基于completion suggest实现搜索提示

suggest,completion suggest,自动完成,搜索推荐,搜索提示 --> 自动完成,auto completion

auto completion

比如说我们在百度,搜索,你现在搜索“大话西游” --> 百度,自动给你提示,“大话西游电影”,“大话西游小说”, “大话西游手游”

不用你把所有你想要输入的文本都输入完,搜索引擎会自动提示你可能是你想要搜索的那个文本

  • 设置mapping
 PUT /news_website
 {
   "mappings": {
     "news" : {
       "properties" : {
         "title" : {
           "type": "text",
           "analyzer": "ik_max_word",
           "fields": {
             "suggest" : {
               "type" : "completion",
               "analyzer": "ik_max_word"
             }
           }
         },
         "content": {
           "type": "text",
           "analyzer": "ik_max_word"
         }
       }
     }
   }
 }

completion,es实现的时候,是非常高性能的,会构建不是倒排索引,也不是正拍索引,就是纯的用于进行前缀搜索的一种特殊的数据结构,而且会全部放在内存中,所以auto completion进行的前缀搜索提示,性能是非常高的

大话西游

  • 插入数据
 PUT /news_website/news/1
 {
   "title": "大话西游电影",
   "content": "大话西游的电影时隔20年即将在2017年4月重映"
 }
 PUT /news_website/news/2
 {
   "title": "大话西游小说",
   "content": "某知名网络小说作家已经完成了大话西游同名小说的出版"
 }
 PUT /news_website/news/3
 {
   "title": "大话西游手游",
   "content": "网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中"
 }
  • 获取数据
 GET /news_website/news/_search
 {
   "suggest": {
     "my-suggest" : {
       "prefix" : "大话西游",
       "completion" : {
         "field" : "title.suggest"
       }
     }
   }
 }
 
 {
   "took": 10,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 0,
     "max_score": 0,
     "hits": []
   },
   "suggest": {
     "my-suggest": [
       {
         "text": "大话西游",
         "offset": 0,
         "length": 4,
         "options": [
           {
             "text": "大话西游小说",
             "_index": "news_website",
             "_type": "news",
             "_id": "2",
             "_score": 1,
             "_source": {
               "title": "大话西游小说",
               "content": "某知名网络小说作家已经完成了大话西游同名小说的出版"
             }
           },
           {
             "text": "大话西游手游",
             "_index": "news_website",
             "_type": "news",
             "_id": "3",
             "_score": 1,
             "_source": {
               "title": "大话西游手游",
               "content": "网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中"
             }
           },
           {
             "text": "大话西游电影",
             "_index": "news_website",
             "_type": "news",
             "_id": "1",
             "_score": 1,
             "_source": {
               "title": "大话西游电影",
               "content": "大话西游的电影时隔20年即将在2017年4月重映"
             }
           }
         ]
       }
     ]
   }
 }
  • 搜索大话西游电影
 GET /news_website/news/_search 
 {
   "query": {
     "match": {
       "content": "大话西游电影"
     }
   }
 }
 
 {
   "took": 2,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 3,
     "max_score": 1.3495269,
     "hits": [
       {
         "_index": "news_website",
         "_type": "news",
         "_id": "1",
         "_score": 1.3495269,
         "_source": {
           "title": "大话西游电影",
           "content": "大话西游的电影时隔20年即将在2017年4月重映"
         }
       },
       {
         "_index": "news_website",
         "_type": "news",
         "_id": "3",
         "_score": 1.217097,
         "_source": {
           "title": "大话西游手游",
           "content": "网易游戏近日出品了大话西游经典IP的手游,正在火爆内测中"
         }
       },
       {
         "_index": "news_website",
         "_type": "news",
         "_id": "2",
         "_score": 1.1299736,
         "_source": {
           "title": "大话西游小说",
           "content": "某知名网络小说作家已经完成了大话西游同名小说的出版"
         }
       }
     ]
   }
 }

Elasticsearch高手进阶篇(77)

elasticsearch高手进阶_使用动态映射模板定制自己的映射策略

dynamic mapping

高级的用法

  • 比如说,我们本来没有某个type,或者没有某个field,但是希望在插入数据的时候,es自动为我们做一个识别,动态映射出这个type的mapping,包括每个field的数据类型, 一般用的动态映射,dynamic mapping

  • 这里有个问题,如果说,我们其实对dynamic mapping有一些自己独特的需求,比如说,es默认来说,如经过识别到一个数字,field: 10,默认是搞成这个field的数据类型是long,再比如说,如果我们弄了一个field : "10",默认就是text,还会带一个keyword的内置field。我们没法改变。

但是我们现在就是希望动态映射的时候,根据我们的需求去映射,而不是让es自己按照默认的规则去完成

dyanmic mapping template(动态映射模板)

我们自己预先定义一个模板,然后插入数据的时候,相关的field,如果能够根据我们预先定义的规则,匹配上某个我们预定义的模板,那么就会根据我们的模板来进行mapping,决定这个Field的数据类型

默认的动态映射的效果咋样
 DELETE /waws_index
 
 PUT /waws_index/waws_type/1
 {
   "test_string": "hello world",
   "test_number": 10
 }

es的自动的默认的,动态映射是咋样的

 GET /waws_index/_mapping/waws_type
 
 {
   "waws_index": {
     "mappings": {
       "waws_type": {
         "properties": {
           "test_number": {
             "type": "long"
           },
           "test_string": {
             "type": "text",
             "fields": {
               "keyword": {
                 "type": "keyword",
                 "ignore_above": 256
               }
             }
           }
         }
       }
     }
   }
 }

这个就是es的默认的动态映射规则,可能就不是我们想要的

我们比如说,现在想要的效果是啥?

  • test_number,如果是个数字,我们希望默认就是integer类型的
  • test_string,如果是字符串,我们希望默认是个text,这个没问题,但是内置的field名字,叫做raw,不叫座keyword,类型还是keyword,保留500个字符
根据类型匹配映射模板
  • 动态映射模板,有两种方式

    • 第一种:是根据新加入的field的默认的数据类型,来进行匹配,匹配上某个预定义的模板;
    • 第二种:是根据新加入的field的名字,去匹配预定义的名字,或者去匹配一个预定义的通配符,然后匹配上某个预定义的模板
  • mapping映射

 PUT /waws_index
 {
   "mappings": {
     "waws_type": {
       "dynamic_templates": [                # 动态模板
         {
           "integers": {                     # 模板的名称
             "match_mapping_type": "long",   # 匹配的类型(插入的数据的类型)
             "mapping": {                    # 映射成的类型
               "type": "integer"
             }
           }
         },
         {
           "strings": {
             "match_mapping_type": "string",
             "mapping": {
               "type": "text",
               "fields": {
                 "raw": {
                   "type": "keyword",
                   "ignore_above": 500
                 }
               }
             }
           }
         }
       ]
     }
   }
 }
  • 插入数据
 PUT /waws_index/waws_type/1
 {
   "test_long": 1,
   "test_string": "hello world"
 }
  • 获取mapping
 GET /waws_index/_mapping/waws_type
 
 {
   "waws_index": {
     "mappings": {
       "waws_type": {
         "dynamic_templates": [
           {
             "integers": {
               "match_mapping_type": "long",
               "mapping": {
                 "type": "integer"
               }
             }
           },
           {
             "strings": {
               "match_mapping_type": "string",
               "mapping": {
                 "fields": {
                   "raw": {
                     "ignore_above": 500,
                     "type": "keyword"
                   }
                 },
                 "type": "text"
               }
             }
           }
         ],
         "properties": {
           "test_long": {
             "type": "integer"
           },
           "test_string": {
             "type": "text",
             "fields": {
               "raw": {
                 "type": "keyword",
                 "ignore_above": 500
               }
             }
           }
         }
       }
     }
   }
 }
根据字段名配映射模板
  • 设置mapping
 PUT /waws_index 
 {
   "mappings": {
     "waws_type": {
       "dynamic_templates": [
         {
           "string_as_integer": {
             "match_mapping_type": "string",
             "match": "long_*",
             "unmatch": "*_text",
             "mapping": {
               "type": "integer"
             }
           }
         }
       ]
     }
   }
 }

举个例子,field : "10",把类似这种field,弄成long型

  • 插入一个数据
 PUT /waws_index/waws_type/1
 {
   "test_long": "1",
   "test_string": "hello world"
 }
  • 获取mapping
 GET /waws_index/_mapping/waws_type
 
 {
   "waws_index": {
     "mappings": {
       "waws_type": {
         "dynamic_templates": [
           {
             "string_as_integer": {
               "match": "long_*",
               "unmatch": "*_text",
               "match_mapping_type": "string",
               "mapping": {
                 "type": "integer"
               }
             }
           }
         ],
         "properties": {
           "test_long": {
             "type": "text",
             "fields": {
               "keyword": {
                 "type": "keyword",
                 "ignore_above": 256
               }
             }
           },
           "test_string": {
             "type": "text",
             "fields": {
               "keyword": {
                 "type": "keyword",
                 "ignore_above": 256
               }
             }
           }
         }
       }
     }
   }
 }

场景,有些时候,dynamic mapping + template,每天有一堆日志,每天有一堆数据

这些数据,每天的数据都放一个新的type中,每天的数据都会哗哗的往新的type中写入,此时你就可以定义一个模板,搞一个脚本,每天都预先生成一个新type的模板,里面讲你的各个Field都匹配到一个你预定义的模板中去,就好了