2018年3月初,萌生了一个想法:对elasticsearch相关的技术书籍做拆解阅读,该想法源自非计算机领域红火已久的【樊登读书会】、得到的每天听本书、xx拆书帮等。
目前市面上elasticsearch的中文书籍就那么基本,针对es5.x以上的三本左右;国外翻译有几本,都是针对es1.x,2.x版本,其中《深入理解elasticsearch》还算比较经典。
拆书的目的:
本次解读是《从lucene到elasticsearch全文检索实战》。
作者是中科院硕士姚攀(90后)在读研究生期间根据实习写成csdn博客,最终成书。
总体评价:
优点:
缺点:
3、核心知识点梳理
以下的dsl都是通过elasticsearchv6.2.2版本试验过的。
1get test_index/test_type/_mget 2{ 3 "docs":[ 4 {"_id":1}, 5 {"_id":3} 6 ] 7}
最小简化版本:
1get test_index/test_type/_mget 2{ 3 "ids":[1,3] 4}
——添加、删除、更新字段
1post test_index/test_type/1 2{ 3 "no":1, 4 "name":"奔驰x100", 5 "addr":"德国", 6 "price":1000000, 7 "tags" : ["red"] 8}
以下添加了新字段tags,赋值为“red”。
1post test_index/test_type/1/_update 2{ 3 "script":"ctx._source.tags = \"red\"" 4}
修改后结果为:
1{ 2 "_index": "test_index", 3 "_type": "test_type", 4 "_id": "1", 5 "_version": 6, 6 "found": true, 7 "_source": { 8 "no": 1, 9 "name": "奔驰x100", 10 "addr": "德国", 11 "price": 1000000, 12 "tags": "red" 13 } 14}
1post test_index/test_type/1/_update 2{ 3 "script":"ctx._source.remove(\"new_field\")" 4}
1post test_index/test_type/1/_update 2{ 3 "script" : { 4 "source": "ctx._source.tags.add(params.tag)", 5 "lang": "painless", 6 "params" : { 7 "tag" : "blue" 8 } 9 } 10}
更新后结果如下:
1{ 2 "_index": "test_index", 3 "_type": "test_type", 4 "_id": "1", 5 "_version": 8, 6 "found": true, 7 "_source": { 8 "no": 1, 9 "name": "奔驰x100", 10 "addr": "德国", 11 "price": 1000000, 12 "tags": [ 13 "red", 14 "blue" 15 ] 16 } 17}
1post test_index/test_type/1/_update 2{ 3 "script" : { 4 "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }", 5 "lang": "painless", 6 "params" : { 7 "tag" : "red" 8 } 9 } 10}
以下是社区的问题,我认为更切合知识点。
线上的场景可能会对一个文档同一秒进行并发修改,导致会出现个别的versionconflictengineexception 异常,我猜测是并发upsert请求 可能存在先获取到版本号的请求 比 后获取到版本号的请求 执行慢或者执行晚导致的,
毕竟默认es不会对文档操作加锁。但是如在不做锁机制的情况下处理这个问题呢。
解决方案(初步):
es版本控制有内部和外部两种类型。默认情况下,es使用内部版本控制。
version_type=external的时候是外部值控制。在使用外部版本类型时,
系统会检查传递给索引请求的版本号是否大于当前存储的文档的版本,
如果为true,则文档将被索引并使用新的版本号。
如果提供的值小于或等于存储文档的版本号,则会发生版本冲突,索引操作将失败。
1put /test_index/test_type/10?version=1520834740000&version_type=external 2{ 3 "newadd":11, 4 "test":"true" 5}
返回结果:
1{ 2 "_index": "test_index", 3 "_type": "test_type", 4 "_id": "10", 5 "_version": 1520834740000, 6 "found": true, 7 "_source": { 8 "newadd": 11, 9 "test": "true" 10 } 11}
所以最简单的实现方式就是每次更新使用当前==时间戳==作为版本号,
不用于排序,很少用于聚合(termsaggrions除外,未来版本会彻底禁止text类型聚合操作)。
题外话:如果需要可以借助 multi-fields.使用:keyword 类型。
官网解读:
对于数字类型的字段,在满足需求的情况下,要尽可能的选择范围小的数字类型。
当用户输入一个查询,elasticsearch通过排序模型计算文档和查询关键词之间的相关度,按照评分排序后返回最想关的文档给用户。
e
细化:elasticsearch接受到关键词以后到倒排索引中进行查询,通过倒排索引中维护的倒排记录表找到关键词对应的文档集合,然后做评分、排序、高亮处理,最终返回搜索结果给用户。
注意:es是按照查询和文档的相关度进行排序的,默认按照评分降序排序。
1get _search 2{ 3 "query":{ 4 "multi_match": { 5 "query": "美国", 6 "fields": ["addr^5", "name"] 7 } 8 } 9}
1get _search 2{ 3 "query":{ 4 "exists":{ 5 "field":"name" 6 } 7 } 8}
1get /_search 2{ 3 "query": { 4 "constant_score" : { 5 "filter" : { 6 "term" : { "addr.keyword" : "美国"} 7 }, 8 "boost" : 1.2 9 } 10 } 11}
返回结果:
1{ 2 "took": 1, 3 "timed_out": false, 4 "_shards": { 5 "total": 32, 6 "successful": 32, 7 "skipped": 0, 8 "failed": 0 9 }, 10 "hits": { 11 "total": 3, 12 "max_score": 1.2, 13 "hits": [ 14 { 15 "_index": "test_index", 16 "_type": "test_type", 17 "_id": "5", 18 "_score": 1.2, 19 "_source": { 20 "no": 5, 21 "name": "福特500", 22 "addr": "美国", 23 "price": 180000 24 } 25 }, 26 { 27 "_index": "test_index", 28 "_type": "test_type", 29 "_id": "6", 30 "_score": 1.2, 31 "_source": { 32 "no": 6, 33 "name": null, 34 "addr": "美国", 35 "price": 180000 36 } 37 }, 38 { 39 "_index": "test_index", 40 "_type": "test_type", 41 "_id": "3", 42 "_score": 1.2, 43 "_source": { 44 "no": 3, 45 "name": "福特300", 46 "addr": "美国", 47 "price": 300000 48 } 49 } 50 ] 51 } 52}
借助:function score query 实现。
1{ 2 "query": { 3 "more_like_this": { 4 "fields": [ 5 "title" 6 ], 7 "like": "新时代的领路人", 8 "min_term_freq": 1, 9 "max_query_terms": 12 10 } 11 }, 12 "_source": "title", 13 "from": 1000, 14 "size": 5 15}
以下内容是6.x验证的。
5.x版本要把source改成inline。
1post test_index/_search 2{ 3 "query":{ 4 "bool":{ 5 "must":{ 6 "script":{ 7 "script":{ 8 "source": "doc['price'].value > 100000", 9 "lang":"painless" 10 } 11 } 12 } 13 } 14 } 15}
字段高亮已经比较熟悉,有一种场景是:当我搜索title字段的时候,我期望高亮:title、content、abstr如何做到呢?
通俗的讲:
不搜索某个字段,可以顺带高亮该字段。
1post test_index/test_type/_search 2{ 3 "query":{ 4 "match_phrase":{ 5 "addr":"美国" 6 } 7 }, 8 "highlight": { 9 "require_field_match":false, 10 "fields":{ 11 "addr":{"pre_tags":["<strong>"], 12 "post_tags":["</strong>"] 13 }, 14 "name":{"pre_tags":["<strong>"], 15 "post_tags":["</strong>"]} 16 } 17 } 18} 1{ 2 "took": 116, 3 "timed_out": false, 4 "_shards": { 5 "total": 5, 6 "successful": 5, 7 "skipped": 0, 8 "failed": 0 9 }, 10 "hits": { 11 "total": 3, 12 "max_score": 1.1143606, 13 "hits": [ 14 { 15 "_index": "test_index", 16 "_type": "test_type", 17 "_id": "6", 18 "_score": 1.1143606, 19 "_source": { 20 "no": 6, 21 "name": "大片美国", 22 "addr": "美国", 23 "price": 180000 24 }, 25 "highlight": { 26 "name": [ 27 "大片<strong>美</strong><strong>国</strong>" 28 ], 29 "addr": [ 30 "<strong>美</strong><strong>国</strong>" 31 ] 32 } 33 }, 34 { 35 "_index": "test_index", 36 "_type": "test_type", 37 "_id": "5", 38 "_score": 0.5753642, 39 "_source": { 40 "no": 5, 41 "name": "福特500", 42 "addr": "美国", 43 "price": 180000 44 }, 45 "highlight": { 46 "addr": [ 47 "<strong>美</strong><strong>国</strong>" 48 ] 49 } 50 }, 51 { 52 "_index": "test_index", 53 "_type": "test_type", 54 "_id": "3", 55 "_score": 0.5753642, 56 "_source": { 57 "no": 3, 58 "name": "福特300", 59 "addr": "美国", 60 "price": 300000 61 }, 62 "highlight": { 63 "addr": [ 64 "<strong>美</strong><strong>国</strong>" 65 ] 66 } 67 } 68 ] 69 } 70}
elasitcsearch 5.4 之后对于text类型的字段,默认采用是bm25评分模型,而不是基于tf-idf的向量空间模型,评分模型的选择可以通过similarity参数在映射中指出。
需要注意的是:es在每个分片上单独打分,分片的数量会影响打分的结果。
这个问题比较有趣的讨论如下:
统计集群的两个方面信息:
一:索引层面
二:节点层面
1get /_cluster/stats
工欲善其事必先利其器,好的工具能提升开发效率。
1、功能介绍:
查看luncene、solr、elasitcsearch索引的gui工具,方便开发和诊断。
2、核心功能点:
3、工具地址:
https://github.com/dmitrykey/luke
4、最新版本
5、注意
luke的版本要和lucene一致。
1、简介
apache tika是一个用于文本检测和文件内容提取的库。
2、特点
tika 可以检测超过1000种不同类型的文档,比如ppt、pdf、doc、xls,所有的文档类型可以通过一个简单的接口被解析。
3、应用
tika广泛应用于搜素引擎、内容分析、文本翻译、数字管理等领域。
4、下载地址
5、扩展
如果有全文知识库检索的项目,可以考虑使用tika对多种不同类型的文档进行文档解析。
此为拆解的第一本书,印证了我之前说的,核心知识点在elasticsearch官网文档中都有更详尽的英文解读。
目前市面上没有一本书能涵盖全部的知识点。
书的目的多半是作者的一些学习、实践积累,更多的知识还得靠实践中总结、实践、再总结。
“书写是为了更好的思考”,与大家共勉!一起加油!
下一本书,紧张梳理中…..
推荐阅读:
为什么选择 spring 作为 java 框架?
springboot rocketmq 整合使用和监控
上篇好文:
如对本文有疑问, 点击进行留言回复!!
[杭电多校2020]第一场 1004 Distinct Sub-palindromes
Swift -- 将本地生成的UIImage进行持久化保存(存到文件中fileManager.createFile)
网友评论