Elasticsearch进阶笔记第三十一篇

179 阅读5分钟

Elasticsearch高手进阶篇(66)

数据建模实战_基于共享锁和排他锁实现悲观锁并发控制

共享锁和排他锁的说明

  • 共享锁:
    • 这份数据是共享的,然后多个线程过来,都可以获取同一个数据的共享锁,然后对这个数据执行读操作
  • 排他锁:
    • 是排他的操作,只能一个线程获取排他锁,然后执行增删改操作
读写锁的分离
  • 如果只是要读取数据的话,那么任意个线程都可以同时进来然后读取数据,每个线程都可以上一个共享锁

  • 但是这个时候,如果有线程要过来修改数据,那么会尝试上排他锁,排他锁会跟共享锁互斥,也就是说,如果有人已经上了共享锁了,那么排他锁就不能上,就得等

    • 如果有人在读数据,就不允许别人来修改数据
    • 如果有人在修改数据,就是加了排他锁
  • 那么其他线程过来要修改数据,也会尝试加排他锁,此时会失败,锁冲突,必须等待,同时只能有一个线程修改数据

  • 如果有人过来同时要读取数据,那么会尝试加共享锁,此时会失败,因为共享锁和排他锁是冲突的

如果有在修改数据,就不允许别人来修改数据,也不允许别人来读取数据

共享锁和排他锁的实验

有人在读数据,其他人也能过来读数据

构建脚本数据judge-lock-2.groovy:

if (ctx.source.lock_type == 'exclusive') { assert false }; ctx. source.lock_count++

 POST /waws_fs/lock/1/_update 
 {
   "upsert": { 
     "lock_type":  "shared",
     "lock_count": 1
   },
   "script": {
     "lang": "groovy",
     "file": "judge-lock-2"
   }
 }
 ​
 POST /waws_fs/lock/1/_update 
 {
   "upsert": { 
     "lock_type":  "shared",
     "lock_count": 1
   },
   "script": {
     "lang": "groovy",
     "file": "judge-lock-2"
   }
 }
  • 获取锁信息
 GET /waws_fs/lock/1
 ​
 {
   "_index": "waws_fs",
   "_type": "lock",
   "_id": "1",
   "_version": 6,
   "found": true,
   "_source": {
     "lock_type": "shared",
     "lock_count": 2
   }
 }

就给大家模拟了,有人上了共享锁,你还是要上共享锁,直接上就行了,没问题,只是lock_count加1

已经有人上了共享锁,然后有人要上排他锁
 PUT /waws_fs/lock/1/_create
 { "lock_type": "exclusive" }
 ​
 {
   "error": {
     "root_cause": [
       {
         "type": "version_conflict_engine_exception",
         "reason": "[lock][1]: version conflict, document already exists (current version [6])",
         "index_uuid": "V98PfLHrRjKrnIkQU5IbPA",
         "shard": "3",
         "index": "waws_fs"
       }
     ],
     "type": "version_conflict_engine_exception",
     "reason": "[lock][1]: version conflict, document already exists (current version [6])",
     "index_uuid": "V98PfLHrRjKrnIkQU5IbPA",
     "shard": "3",
     "index": "waws_fs"
   },
   "status": 409
 }

排他锁用的不是upsert语法,create语法,要求lock必须不能存在,直接自己是第一个上锁的人,上的是排他锁

如果已经有人上了共享锁,明显/waws_fs/lock/1是存在的,create语法去上排他锁,肯定会报错

对共享锁进行解锁
 PUT /waws_fs/lock/_bulk
 { "delete": { "_id": 1}}

连续解锁3次,此时共享锁就彻底没了

每次解锁一个共享锁,就对lock_count先减1,如果减了1之后,是0,那么说明所有的共享锁都解锁完了,此时就就将/fs/lock/1删除,就彻底解锁所有的共享锁

上排他锁,再上排他锁
 PUT /waws_fs/lock/1/_create
 { "lock_type": "exclusive" }

其他线程

 PUT /waws_fs/lock/1/_create
 { "lock_type": "exclusive" }
 ​
 {
   "error": {
     "root_cause": [
       {
         "type": "version_conflict_engine_exception",
         "reason": "[lock][1]: version conflict, document already exists (current version [1])",
         "index_uuid": "V98PfLHrRjKrnIkQU5IbPA",
         "shard": "3",
         "index": "waws_fs"
       }
     ],
     "type": "version_conflict_engine_exception",
     "reason": "[lock][1]: version conflict, document already exists (current version [1])",
     "index_uuid": "V98PfLHrRjKrnIkQU5IbPA",
     "shard": "3",
     "index": "waws_fs"
   },
   "status": 409
 }
上排他锁,上共享锁
 POST /waws_fs/lock/1/_update 
 {
   "upsert": { 
     "lock_type":  "shared",
     "lock_count": 1
   },
   "script": {
     "lang": "groovy",
     "file": "judge-lock-2"
   }
 }
 
 {
   "error": {
     "root_cause": [
       {
         "type": "remote_transport_exception",
         "reason": "[w85Pu0f][127.0.0.1:9300][indices:data/write/update[s]]"
       }
     ],
     "type": "illegal_argument_exception",
     "reason": "failed to execute script",
     "caused_by": {
       "type": "script_exception",
       "reason": "error evaluating judge-lock-2",
       "caused_by": {
         "type": "power_assertion_error",
         "reason": "assert false\n"
       },
       "script_stack": [],
       "script": "",
       "lang": "groovy"
     }
   },
   "status": 400
 }
解锁排他锁
 DELETE /waws_fs/lock/1

Elasticsearch高手进阶篇(67)

数据建模实战_基于nested object实现博客与评论嵌套关系

nested object

冗余数据方式的来建模,其实用的就是object类型,我们这里又要引入一种新的object类型,nested object类型

博客,评论,做的这种数据模型

 PUT /waws_webblog/blogs/6
 {
   "title": "花无缺发表的一篇帖子",
   "content":  "我是花无缺,大家要不要考虑一下投资房产和买股票的事情啊。。。",
   "tags":  [ "投资", "理财" ],
   "comments": [ 
     {
       "name":    "小鱼儿",
       "comment": "什么股票啊?推荐一下呗",
       "age":     28,
       "stars":   4,
       "date":    "2016-09-01"
     },
     {
       "name":    "黄药师",
       "comment": "我喜欢投资房产,风,险大收益也大",
       "age":     31,
       "stars":   5,
       "date":    "2016-10-22"
     }
   ]
 }

被年龄是28岁的黄药师评论过的博客,搜索

 GET /waws_webblog/blogs/_search
 {
   "query": {
     "bool": {
       "must": [
         { "match": { "comments.name": "黄药师" }},
         { "match": { "comments.age":  28      }} 
       ]
     }
   }
 }
 
 {
   "took": 6,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 1,
     "max_score": 1.8022683,
     "hits": [
       {
         "_index": "waws_webblog",
         "_type": "blogs",
         "_id": "6",
         "_score": 1.8022683,
         "_source": {
           "title": "花无缺发表的一篇帖子",
           "content": "我是花无缺,大家要不要考虑一下投资房产和买股票的事情啊。。。",
           "tags": [
             "投资",
             "理财"
           ],
           "comments": [
             {
               "name": "小鱼儿",
               "comment": "什么股票啊?推荐一下呗",
               "age": 28,
               "stars": 4,
               "date": "2016-09-01"
             },
             {
               "name": "黄药师",
               "comment": "我喜欢投资房产,风,险大收益也大",
               "age": 31,
               "stars": 5,
               "date": "2016-10-22"
             }
           ]
         }
       }
     ]
   }
 }

结果是好像不太对啊

object类型数据结构的底层存储

 {
   "title":[ "花无缺", "发表", "一篇", "帖子" ],
   "content":[ "我", "是", "花无缺", "大家", "要不要", "考虑", "一下", "投资", "房产", "买", "股票", "事情" ],
   "tags":[ "投资", "理财" ],
   "comments.name":[ "小鱼儿", "黄药师" ],
   "comments.comment":[ "什么", "股票", "推荐", "我", "喜欢", "投资", "房产", "风险", "收益", "大" ],
   "comments.age":[ 28, 31 ],
   "comments.stars":[ 4, 5 ],
   "comments.date":[ 2016-09-01, 2016-10-22 ]
 }

object类型底层数据结构,会将一个json数组中的数据,进行扁平化

所以,直接命中了这个document,name=黄药师,age=28,正好符合

引入nested object类型,来解决object类型底层数据结构导致的问题

修改mapping,将comments的类型从object设置为nested

 # 先删除所有数据
 DELETE /waws_webblog
 
 PUT /waws_webblog
 {
   "mappings": {
     "blogs": {
       "properties": {
         "comments": {
           "type": "nested", 
           "properties": {
             "name":    {"type": "string"},
             "comment": {"type": "string"},
             "age":     {"type": "short"},
             "stars":   {"type": "short"},
             "date":    {"type": "date"}
           }
         }
       }
     }
   }
 }
 
 { 
   "comments.name":[ "小鱼儿" ],
   "comments.comment":[ "什么", "股票", "推荐" ],
   "comments.age":[ 28 ],
   "comments.stars":[ 4 ],
   "comments.date":[ 2014-09-01 ]
 }
 { 
   "comments.name":[ "黄药师" ],
   "comments.comment":[ "我", "喜欢", "投资", "房产", "风险", "收益", "大" ],
   "comments.age":[ 31 ],
   "comments.stars":[ 5 ],
   "comments.date":[ 2014-10-22 ]
 }
 { 
   "title":[ "花无缺", "发表", "一篇", "帖子" ],
   "body":[ "我", "是", "花无缺", "大家", "要不要", "考虑", "一下", "投资", "房产", "买", "股票", "事情" ],
   "tags":[ "投资", "理财" ]
 }

再次搜索,成功了

 GET /waws_webblog/blogs/_search 
 {
   "query": {
     "bool": {
       "must": [
         {
           "match": {
             "title": "花无缺"
           }
         },
         {
           "nested": {
             "path": "comments",
             "query": {
               "bool": {
                 "must": [
                   {
                     "match": {
                       "comments.name": "黄药师"
                     }
                   },
                   {
                     "match": {
                       "comments.age": 28
                     }
                   }
                 ]
               }
             }
           }
         }
       ]
     }
   }
 }
 ​
 {
   "took": 13,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 0,
     "max_score": null,
     "hits": []
   }
 }
  • score_mode:max,min,avg,none,默认是avg
    • 如果搜索命中了多个nested document,如何讲个多个nested document的分数合并为一个分数