电商项目——全文检索-ElasticSearch——第一章——中篇 电商项目——商城业务-商品上架——第二章——中篇 电商项目——商城业务-首页——第三章——中篇 电商项目——性能压测——第四章——中篇 电商项目——缓存——第五章——中篇
电商项目所有的检索功能都是用ElasticSearch构建起来的,全文检索的数据都是来自mysql,以后我们要把mysql的数据给ES存储一份,这样ES才可以将数据检索出来 lasticSearch——ElasticSearch和Kibana介绍
Elasticsearch是一个分布式的、RESTful的搜索和分析引擎,能够解决越来越多的用例。作为弹性堆栈的核心,它集中存储数据,以便您可以发现预期的数据和发现意外的数据。ElassticSearch的数据默认放在内存中(进行分析检索是非常快的)
Docker下安装Redis和Mysql,elasticsearch,Kibana,nginx——简洁篇 我在使用Vagrant中拉取ES镜像报如下错误
结果分析发现是 /var/lib/docker/overlay2/路径下的联合目录挂载文件系统,满了
& df -hl #查看存储分布情况以下的博客对我理解上面的问题有一定的帮助 docker的overlay2笔记 /var/lib/docker/overlay2 占用很大,清理Docker占用的磁盘空间,迁移 /var/lib/docker 目录 sda, sdb, sdc, sda1, sda2在Linux中都代表什么
最终的解决办法,我就只可重新安装一遍虚拟机
如下是在docker中查找镜像的位置和容器所在位置的命令 docker查看镜像仓库的位置
Docker下安装Redis和Mysql,elasticsearch,Kibana,nginx——简洁篇
ES作为存储分析检索的一个引擎,我们先来体会它的存储功能,先来对它进行增删改查,在进行这个之前,我们先来体会一下_cat,我们说对所有的ES操作,ES都封装成了API发送请求进行,我们就使用postman进行如下测试
GET:http://192.168.56.10:9200/_cat/nodes 127.0.0.1 60 95 0 0.00 0.04 0.05 dilm * 5f28b7a757f5 GET:http://192.168.56.10:9200/_cat/health 1603399251 20:40:51 elasticsearch green 1 1 0 0 0 0 0 0 - 100.0% GET:http://192.168.56.10:9200/_cat/master 08ZJHzRhQzipECG4ADz0mg 127.0.0.1 127.0.0.1 5f28b7a757f5 GET:http://192.168.56.10:9200/_cat/indices #装好了kibnana,也会给es中存储一些kibana一些节点信息 green open .kibana_task_manager_1 1CyCbE1ETFOFC7se-K1T9Q 1 0 2 0 38.2kb 38.2kb green open .apm-agent-configuration wQZkBe1bRgu7bJW28RDNhg 1 0 0 0 283b 283b green open .kibana_1 qKYKuXT_S86Zdtlj6H3u8A 1 0 5 0 18.3kb 18.3kb#发送多次是一个更新操作 PUT:http://192.168.56.10:9200/customer/external/1 { "name":"zlj" } { "_index": "customer", #在哪个索引下(数据库)被创建 "_type": "external", #在哪个类型下(表)被创建 "_id": "1", #数据id "_version": 1, #版本号(不断叠加过程) "result": "created", "_shards": { # 分片(集群用到) "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 } PUT:http://192.168.56.10:9200/customer/external/1 { "name":"zlj" } { "_index": "customer",#在哪个索引下(数据库)被创建 "_type": "external", #在哪个类型下(表)被创建 "_id": "1", #数据id "_version": 2, #版本号(不断叠加过程) "result": "updated", "_shards": { # 分片(集群用到) "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1 }
我们在使用_cat查找索引发现,customer被成功添加
GET:http://192.168.56.10:9200/_cat/indices green open .kibana_task_manager_1 1CyCbE1ETFOFC7se-K1T9Q 1 0 2 0 38.2kb 38.2kb green open .apm-agent-configuration wQZkBe1bRgu7bJW28RDNhg 1 0 0 0 283b 283b green open .kibana_1 qKYKuXT_S86Zdtlj6H3u8A 1 0 5 0 18.3kb 18.3kb yellow open customer w3rhRLUsTWWx_lC_XN08LQ 1 1 1 0 3.3kb 3.3kb #不指定id,会自动生成id。指定了id就会修改这个数据 POST:http://192.168.56.10:9200/customer/external { "name":"zlj" } { "_index": "customer", #在哪个索引下(数据库)被创建 "_type": "external", #在哪个类型下(表)被创建 "_id": "sWomU3UBynfGwnzRowT3", #数据id "_version": 1, #版本号(不断叠加过程) "result": "created", # 分片(集群用到) "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1 }比如A看到这个数据是1,B,C,D看到的也都是1,这个时候,A想把1改成2,B想把1改成3,C想把1改成4,D想把1改成5,这个时候如果B先到达es,A后到达es(A的本意是想把1改成2的,如果是别的值就算了),这个时候我们就可以使用乐观锁,比如B先到达es,把值改了,这个时候_seq_no+1,A想进来修改就先判断这个值,如果_seq_no值是1才进行修改,如果是其他值就不会进行修改,我们来模拟上面操作 我们来进行修改下面name=zlj的数据
GET:http://192.168.56.10:9200/customer/external/1 { "_index": "customer", "_type": "external", "_id": "1", "_version": 3, "_seq_no": 2, "_primary_term": 1, "found": true, "_source": { "name": "zlj" } }我门创建如下两个请求,按顺序执行,并带上?if_seq_no=2&if_primary_term=1字段(值和查询出的数据响应结果对应)
PUT:http://192.168.56.10:9200/customer/external/1 { "name":"1" } { "_index": "customer", "_type": "external", "_id": "1", "_version": 4, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 5, #不断叠加,下次还想要乐观锁进行修改,就要使用这个数据 "_primary_term": 1 } PUT:http://192.168.56.10:9200/customer/external/1?if_seq_no=2&if_primary_term=1 { "name":"2" } { "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[1]: version conflict, required seqNo [2], primary term [1]. current document has seqNo [5] and primary term [1]", "index_uuid": "w3rhRLUsTWWx_lC_XN08LQ", "shard": "0", "index": "customer" } ], "type": "version_conflict_engine_exception", "reason": "[1]: version conflict, required seqNo [2], primary term [1]. current document has seqNo [5] and primary term [1]", "index_uuid": "w3rhRLUsTWWx_lC_XN08LQ", "shard": "0", "index": "customer" }, "status": 409 } #因为我们执行第一个请求后 "_seq_no": 5,发生了改变,所以报 "reason": "[1]: version conflict, required seqNo [2], primary term [1]. current document has seqNo [5] and primary term [1]", #我们想要修改成功执行如下命令即可 PUT:http://192.168.56.10:9200/customer/external/1?if_seq_no=5&if_primary_term=1 { "name":"2" } { "_index": "customer", "_type": "external", "_id": "1", "_version": 5, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 6,#不断叠加,下次还想要乐观锁进行修改,就要使用这个数据 "_primary_term": 1 }#使用_update POST:http://192.168.56.10:9200/customer/external/1/_update { "doc":{ "name":"zlj" } } { "_index": "customer", "_type": "external", "_id": "1", "_version": 6, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 7, "_primary_term": 1 } #我们再次执行发现响应发生如下变化 POST:http://192.168.56.10:9200/customer/external/1/_update { "doc":{ "name":"zlj" } } { "_index": "customer", "_type": "external", "_id": "1", "_version": 6, "result": "noop", "_shards": { "total": 0, "successful": 0, "failed": 0 }, "_seq_no": 7, "_primary_term": 1 } #使用_update就是对比原来数据,与原来一样就什么都不做,序列号(_seq_no)不变的 和版本号(version)不会往上加,操作也就是noop不做任何操作, POST:http://192.168.56.10:9200/customer/external/1/ { "name":"zlj" } { "_index": "customer", "_type": "external", "_id": "1", "_version": 7, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 8, "_primary_term": 1 } #我们再次执行发现响应发生如下变化 POST:http://192.168.56.10:9200/customer/external/1/ { "name":"zlj" } { "_index": "customer", "_type": "external", "_id": "1", "_version": 8, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 9, "_primary_term": 1 } #不使用_update就不会检查原数据序列号(_seq_no)变的和版本号(version)会往上加, 操作也就是updated不断更新,使用PUT跟使用POST不带_dpdate一样
使用post不带_update,post带_updat,put都可以
POST:http://192.168.56.10:9200/customer/external/1/ { "name":"zlj", "age":20 } { "_index": "customer", "_type": "external", "_id": "1", "_version": 9, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 10, "_primary_term": 1 } POST:http://192.168.56.10:9200/customer/external/1/_update { "doc": { "name":"zlj", "age":20 } } { "_index": "customer", "_type": "external", "_id": "1", "_version": 11, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 12, "_primary_term": 1 }我们现在批量的给索引中导入一些数据,进行复杂的检索功能 bulk批量API 我们使用kibana进行测试
#post新增不要带id,put新增要带id POST /customer/external/_bulk {"index":{"_id":"1"}} {"name":"zlj"} {"index":{"_id":"2"}} {"name":"zzz"} { "took" : 5, "errors" : false, "items" : [ { "index" : { "_index" : "customer", "_type" : "external", "_id" : "1", "_version" : 2, "result" : "updated", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 16, "_primary_term" : 1, "status" : 200 } }, { "index" : { "_index" : "customer", "_type" : "external", "_id" : "2", "_version" : 2, "result" : "updated", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 17, "_primary_term" : 1, "status" : 200 } } ] }我们批量插入如下数据,方便以后进行测试 https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json
POST /bank/account/_bulk {//......}所有的学习都要参照官方文档
1)检索信息 在kibana中进行测试
GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] } #响应的hits部分包括匹配搜索条件的前10个文档: { "took" : 25, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1000, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "bank", "_type" : "account", "_id" : "0", "_score" : null, "_source" : { "account_number" : 0, "balance" : 16623, "firstname" : "Bradshaw", "lastname" : "Mckenzie", "age" : 29, "gender" : "F", "address" : "244 Columbus Place", "employer" : "Euron", "email" : "bradshawmckenzie@euron.com", "city" : "Hobucken", "state" : "CO" }, "sort" : [ 0 ] }, { "_index" : "bank", "_type" : "account", "_id" : "1", "_score" : null, "_source" : { "account_number" : 1, "balance" : 39225, "firstname" : "Amber", "lastname" : "Duke", "age" : 32, "gender" : "M", "address" : "880 Holmes Lane", "employer" : "Pyrami", "email" : "amberduke@pyrami.com", "city" : "Brogan", "state" : "IL" }, "sort" : [ 1 ] }, //................. ] } } #要翻页搜索结果,请在请求中指定from和size参数。 #每个搜索请求都是自包含的:Elasticsearch不会跨请求维护任何状态信息 GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ], "from": 10, "size": 10 }GET /bank/_search { # 一个查询语句的典型结构 "query": { "match_phrase": { "balance": "26135" } }, # 针对某个字段的结构 "sort": [ { "balance": { "order": "desc" } } ] }
返回部分字段的体验
GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "balance": { "order": "desc" } } ], "from": 9, "size": 10, "_source": ["age","balance"] }要在字段中搜索特定的术语,可以使用match查询。例如,下面的请求搜索地址字段以查找地址包含mill或lane的客户:
GET /bank/_search { "query": { "match": { "address": "mill lane" } } }要执行短语搜索而不是匹配单个术语,可以使用match_phrase而不是match。例如,下面的请求只匹配包含短语mill lane的地址:
GET /bank/_search { "query": { "match_phrase": { "address": "mill lane" } } }要构造更复杂的查询,可以使用bool查询组合多个查询条件。您可以根据需要(must match)、需要(should match)或不需要(must not match)指定标准。 例如,以下请求在银行索引中搜索属于40岁客户的账户,但不包括居住在爱达荷州的客户(ID):
GET /bank/_search { "query": { "bool": { "must": [ { "match": { "age": "40" } } ], "must_not": [ { "match": { "state": "ID" } } ] } } }bool查询中的每个must、should和must_not元素被称为查询子句。**文档满足每个must或should子句中的标准的程度将决定文档的相关性得分。得分越高,文档越符合您的搜索条件。**默认情况下,Elasticsearch返回按相关度评分排序的文档。
must_not子句中的条件被视为筛选器。它影响结果中是否包含文档,但不影响如何对文档进行评分。我们还可以显式地指定任意过滤器,以基于结构化数据包含或排除文档。
例如,下面的请求使用范围筛选器将结果限制为余额在$20,000到$30,000之间的账户。
GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } }第14章节已经介绍了
精确字段用term,全文检索用query
返回在所提供的字段中包含确切术语的文档。"que可以使用term query根据精确的值(如价格、产品ID或用户名)来查找文档。默认情况下,Elasticsearch在分析时更改文本字段的值。这可能使查找文本字段值的精确匹配变得困难。要搜索文本字段值,请使用匹配查询。 GET /bank/_search { "query": { "term": { "age": "24" } } } GET /bank/_search { "query": { "term": { "address": "583 Ainslie Street" } } }示例1:搜索address中包含mill的所有人的年龄以及平均年龄#,以及平均薪资
#搜索address中包含mill的所有人的年龄以及平均年龄#,以及平均薪资 GET /bank/_search { "query": { "match": { "address": "mill" } } , "aggs": { "ageAgg": { "terms": { "field": "age", "size": 10 } }, "ageAvg": { "avg": { "field": "age" } }, "balanceAvg": { "avg": { "field": "balance" } } }, "size": 0 }示例2: 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
# 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资 GET /bank/_search { "query": { "match_all": {} }, "aggs": { "ageAgg": { "terms": { "field": "age", "size": 1000 }, "aggs": { "balanceAvg": { "avg": { "field": "balance" } } } } } }示例3:查出所有年龄分布,并且这些年龄段中的M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
#查出所有年龄分布,并且这些年龄段中的M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资 GET /bank/_search { "query": { "match_all": {} }, "aggs": { "ageAgg": { "terms": { "field": "age", "size": 10 }, "aggs": { "balanceAgg": { "terms": { "field": "balance", "size": 10 }, "aggs": { "balanceAvg": { "avg": { "field": "balance" } } } }, "balanceAvgTotal": { "avg": { "field": "balance" } } } } } }可以使用create index API创建具有显式映射的新索引。格式
PUT /my-index-000001 { "mappings": { "properties": { "age": { "type": "integer" }, "email": { "type": "keyword" }, "name": { "type": "text" } } } }示例:创建一个新的索引更改年龄的类型,并且移交给bank的索引
#创建一个新索引 PUT /newbank { "mappings": { "properties": { "account_number": { "type": "long" }, "address": { "type": "text" }, "age": { "type": "integer" }, "balance": { "type": "long" }, "city": { "type": "keyword" }, "email": { "type": "keyword" }, "employer": { "type": "keyword" }, "firstname": { "type": "text" }, "gender": { "type": "keyword" }, "lastname": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "state": { "type": "keyword" } } } } #执行如下命令进行数据迁移
ES中的标准分词器介绍 开启密码登录在虚拟机中
ES官网中默认的分词器都是只支持英文的,,如果要想支持中文,我们要安装ik分词器
我们一些流行用语,ik检测不出来,我就要使用扩展的自定义词库来进行鉴别 最简单的方法就是修改ik分词器的IKAnalyzer.cfg.xml配置文件,指定远程词库,向远程词库发送请求,要到最新的词,作为新的词源进行分解,所以我们有两种方式 第一种:自己写一个项目来接受请求,对词源进行分解 第二种:安装nginx,把最新词库放在nginx中,在配置文件中向nginx发送请求,得到最新的词源 安装nginx Nginx——Nginx简介 Docker下安装Redis和Mysql,elasticsearch,Kibana,nginx——简洁篇 nginx默认访问html文件中的index.html,输入虚拟机ip地址即可(nginx找资源都是在html的路径下找) 我的nginx访问失败,如下博客对我有帮助 关于Nginx启动成功,浏览器不能访问的解决办法 centos出现“FirewallD is not running”怎么办 -bash: netstat: command not found 扩展自定义词库步骤 第一步:在nginx中编写一个默认的fenci_ik.txt分词库(一些流行用语)
vi fenci_ik.txt第二步:修改ik分词器的配置
SpringBoot整合ES
SpringBoot整合ES