Elasticsearch进阶笔记第一篇

608 阅读6分钟

Elasticsearch高手进阶篇(1)

结构化搜索_IT技术论坛案例背景介绍

案例背景:IT技术论坛

  • IT技术论坛中相关的数据,会在es中建立数据的索引

    • 深度讲解搜索数据分析数据建模

IT技术论坛,发各种IT技术的帖子:一种是自己研究了一个技术,就发出来一些研究心得;自己遇到了问题,发个帖子问一问。帖子会有人回复,还会有人浏览。当然了,还有一些论坛会提供简单社交的一个功能,互相加好友,互相关注,互相点赞,之类的。

在IT技术论坛的背景下,去开发一些跟案例背景相关的搜索或者数据分析,或者数据建模的需求,用每一讲学到的知识点,去接解决一些问题

既可以学到知识和技术,也可以在真实的案例背景中练习一下学到的东西

Elasticsearch高手进阶篇(2)

结构化搜索_在案例中实战使用term filter来搜索数据

1、根据用户ID、是否隐藏、帖子ID、发帖日期来搜索帖子

(1)插入一些测试帖子数据

 POST /waws/article/_bulk
 { "index": { "_id": 1 }}
 { "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" }
 { "index": { "_id": 2 }}
 { "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" }
 { "index": { "_id": 3 }}
 { "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" }
 { "index": { "_id": 4 }}
 { "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }

初步来说,就先搞4个字段,因为整个es是支持json document格式的,所以说扩展性和灵活性非常之好。如果后续随着业务需求的增加,要在document中增加更多的field,那么我们可以很方便的随时添加field。但是如果是在关系型数据库中,比如mysql,我们建立了一个表,现在要给表中新增一些column,那就很坑爹了,必须用复杂的修改表结构的语法去执行。而且可能对系统代码还有一定的影响

 GET /waws/_mapping/article
 
 {
   "waws": {
     "mappings": {
       "article": {
         "properties": {
           "articleID": {
             "type": "text",
             "fields": {
               "keyword": {
                 "type": "keyword",
                 "ignore_above": 256
               }
             }
           },
           "hidden": {
             "type": "boolean"
           },
           "postDate": {
             "type": "date"
           },
           "userID": {
             "type": "long"
           }
         }
       }
     }
   }
 }
  • 现在es 5.2版本,type=text, 默认会设置两个field

    • 一个是field本身,比如articleID,就是分词的;
    • 还有一个的话,就是field.keyword,articleID.keyword,默认不分词,会最多保留256个字符
     # 查看字段的分词器
     GET /waws/_analyze
     {
       "field": "article.articleID",
       "text":"KDKE-B-9947-#kL5"
     }
     
     {
       "tokens": [
         {
           "token": "kdke",
           "start_offset": 0,
           "end_offset": 4,
           "type": "<ALPHANUM>",
           "position": 0
         },
         {
           "token": "b",
           "start_offset": 5,
           "end_offset": 6,
           "type": "<ALPHANUM>",
           "position": 1
         },
         {
           "token": "9947",
           "start_offset": 7,
           "end_offset": 11,
           "type": "<NUM>",
           "position": 2
         },
         {
           "token": "kl5",
           "start_offset": 13,
           "end_offset": 16,
           "type": "<ALPHANUM>",
           "position": 3
         }
       ]
     }
     
     # 使用的是keyword的方式我们看到,并不分词
     GET /waws/_analyze
     {
       "field": "articleID.keyword",
       "text":"KDKE-B-9947-#kL5"
     }
     
     {
       "error": {
         "root_cause": [
           {
             "type": "remote_transport_exception",
             "reason": "[w85Pu0f][127.0.0.1:9300][indices:admin/analyze[s]]"
           }
         ],
         "type": "illegal_argument_exception",
          # 原因:不支持分词
         "reason": "Can't process field [articleID.keyword], Analysis requests are only supported on tokenized fields"
       },
       "status": 400
     }
    
    • 使用"articleID" : "XHDK-A-1293-#fJ3"搜索不到任何数据的原因:
      • 默认是analyzed的text类型的field,建立倒排索引的时候,就会对所有的articleID分词,分词以后,原本的articleID就没有了,只有分词后的各个word存在于倒排索引中

      • term,是不对搜索文本分词的,XHDK-A-1293-#fJ3 --> XHDK-A-1293-#fJ3;但是articleID建立索引的时候,XHDK-A-1293-#fJ3 --> xhdk,a,1293,fj3

    总结就是:我们的数据类型是text的,默认会进行分词,将分词数据放在倒排索引中,然后我们使用字段的整体的数据进行匹配的话,并不能索引到,所以我们可以使用articleID.keyword的整体的方式进行匹配。

(2)根据用户ID搜索帖子

 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "userID" : 1
                 }
             }
         }
     }
 }
 ​
 {
   "took": 61,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 2,
     "max_score": 1,
     "hits": [
       {
         "_index": "waws",
         "_type": "article",
         "_id": "2",
         "_score": 1,
         "_source": {
           "articleID": "KDKE-B-9947-#kL5",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-02"
         }
       },
       {
         "_index": "waws",
         "_type": "article",
         "_id": "1",
         "_score": 1,
         "_source": {
           "articleID": "XHDK-A-1293-#fJ3",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-01"
         }
       }
     ]
   }
 }
  • term filter/query(重要):对搜索文本不分词,直接拿去倒排索引中匹配,你输入的是什么,就去匹配什么,比如说,如果对搜索文本进行分词的话,“helle world” --> “hello”和“world”,两个词分别去倒排索引中匹配term,“hello world” --> “hello world”,直接去倒排索引中匹配“hello world”

(3)搜索没有隐藏的帖子

 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "hidden" : false
                 }
             }
         }
     }
 }
 
 {
   "took": 4,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 3,
     "max_score": 1,
     "hits": [
       {
         "_index": "waws",
         "_type": "article",
         "_id": "2",
         "_score": 1,
         "_source": {
           "articleID": "KDKE-B-9947-#kL5",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-02"
         }
       },
       {
         "_index": "waws",
         "_type": "article",
         "_id": "1",
         "_score": 1,
         "_source": {
           "articleID": "XHDK-A-1293-#fJ3",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-01"
         }
       },
       {
         "_index": "waws",
         "_type": "article",
         "_id": "3",
         "_score": 1,
         "_source": {
           "articleID": "JODL-X-1937-#pV7",
           "userID": 2,
           "hidden": false,
           "postDate": "2017-01-01"
         }
       }
     ]
   }
 }

(4)根据发帖日期搜索帖子

 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "postDate" : "2017-01-01"
                 }
             }
         }
     }
 }

(5)根据帖子ID搜索帖子

 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "articleID" : "XHDK-A-1293-#fJ3"
                 }
             }
         }
     }
 }
 
 {
   "took": 1,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 0,
     "max_score": null,
     "hits": []
   }
 }
 
 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "articleID.keyword" : "XHDK-A-1293-#fJ3"
                 }
             }
         }
     }
 }
 
 {
   "took": 1,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 1,
     "hits": [
       {
         "_index": "waws",
         "_type": "article",
         "_id": "1",
         "_score": 1,
         "_source": {
           "articleID": "XHDK-A-1293-#fJ3",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-01"
         }
       }
     ]
   }
 }
  • articleID.keyword,是es最新版本内置建立的field,就是不分词的。所以一个articleID过来的时候,会建立两次索引,一次是自己本身,是要分词的,分词后放入倒排索引;另外一次是基于articleID.keyword,不分词,保留256个字符最多,直接一个字符串放入倒排索引中。

  • term filter,对text过滤,可以考虑使用内置的field.keyword来进行匹配。但是有个问题,默认就保留256个字符。所以尽可能还是自己去手动建立索引,指定not_analyzed吧。在最新版本的es中,不需要指定not_analyzed也可以,将type=keyword即可。

(6)重建索引

 DELETE /waws
 ​
 PUT /waws
 {
   "mappings": {
     "article": {
       "properties": {
         "articleID": {
           "type": "keyword"
         }
       }
     }
   }
 }

重新输入数据

 POST /waws/article/_bulk
 { "index": { "_id": 1 }}
 { "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" }
 { "index": { "_id": 2 }}
 { "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" }
 { "index": { "_id": 3 }}
 { "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" }
 { "index": { "_id": 4 }}
 { "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }

(7)重新根据帖子ID和发帖日期进行搜索

 GET /waws/article/_search
 {
     "query" : {
         "constant_score" : { 
             "filter" : {
                 "term" : { 
                     "articleID" : "XHDK-A-1293-#fJ3"
                 }
             }
         }
     }
 }
 
 {
   "took": 1,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 1,
     "hits": [
       {
         "_index": "waws",
         "_type": "article",
         "_id": "1",
         "_score": 1,
         "_source": {
           "articleID": "XHDK-A-1293-#fJ3",
           "userID": 1,
           "hidden": false,
           "postDate": "2017-01-01"
         }
       }
     ]
   }
 }

2、梳理学到的知识点

(1)term filter:根据exact value进行搜索,数字、boolean、date天然支持

(2)text需要建索引时指定为not_analyzed,才能用term query

(3)相当于SQL中的单个where条件

select * from forum.article where articleID='XHDK-A-1293-#fJ3'