ToB企服应用市场:ToB评测及商务社交产业平台

标题: 全文检索-ElasticSearch [打印本页]

作者: 兜兜零元    时间: 2024-6-20 22:28
标题: 全文检索-ElasticSearch

1.基本概念

1.Index索引

动词:相当于MySQL中的insert;
名词:相当于MySQL中的DataBase;
2.Type(类型)

在Index(索引)中,可以定义一个或多个类型
类似于MySQL中的Table;每一种类型的数据放在一起
3.Document(文档)

保存在某个索引(index)下,某种类型(Type) 的一个数据(Document),文档是JSON格式的,Document就像是MySQL 中的某个Table里面的内容 类似一行数据

4.倒排索引


2.Docker 安装ElasticSearch

2.1 拉取镜像

  1. docker pull elasticsearch:7.4.2
复制代码
  1. docker pull kibana:7.4.2
复制代码
2.2 创建实例

2.2.1 创建挂载目次

  1. mkdir  ./config
复制代码
  1. mkdir ./data
复制代码
 记得授予权限
  1. chmod -R 777 ./elasticsearch
复制代码
2.2.2 使容器外任何地址都能够访问 elasticsearch

  1. echo "http.host: 0.0.0.0
  2. ">>./config/elasticsearch.yml
复制代码
elasticsearch.yml
  1. http.host: 0.0.0.0
复制代码

2.2.3 docker 启动

  1. docker run --name elasticsearch -p 9200:9200 -p9300:9300 \
  2. -e "discovery.type=single-node" \
  3. -e ES_JAVA_OPTS="-Xms512m -Xmx1024m" \
  4. -v ./config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
  5. -v ./data:/usr/share/elasticsearch/data \
  6. -v ./plugins:/usr/share/elasticsearch/plugins \
  7. -d elasticsearch:7.4.2
复制代码

2.3 安装Kibana

  1. docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.232.209:9200 -p 5601:5601 \
  2. -d kibana:7.4.2
复制代码

 3.初步检索

3.1 _cat 

检察节点信息

  1. http://192.168.232.209:9200/_cat/nodes
复制代码
检察elasticsearch的健康状态

  1. http://192.168.232.209:9200/_cat/health
复制代码
检察elasticsearch的主节点信息

  1. http://192.168.232.209:9200/_cat/master
复制代码
检察所有索引

  1. http://192.168.232.209:9200/_cat/indices
复制代码
3.2 索引一个文档(保存或修改一条记录)

保存一个数据,保存在那个索引的哪个类型下,指定用哪个唯一标识
  1. http://192.168.232.209:9200/customer/external/1
复制代码

 3.3 查询文档 

  1. http://192.168.232.209:9200/customer/external/1
复制代码
3.4 更新文档 


3.4.1 _update

这个操纵假如修改文档的值和原来一样,则不会更新版本。
3.4.2 


3.5 删除文档


3.6 bulk 批量 API


批量操纵 

从这个网站复制
  1. https://gitee.com/xlh_blog/common_content/blob/master/es%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE.json#
复制代码
执行 /_bluk 

 4.进阶检索

1.searchAPI

ES支持两种基本方式检索:

  1. GET /bank/_search?q=*&sort=account_number:asc
复制代码
q=* 查询所有
sort 跟据 account_number 升序
2.QueryDSL



  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match_all": {}
  5.   },
  6.   "sort": [
  7.     {
  8.       "account_number":  "asc"
  9.     },
  10.     {
  11.       "balance": "desc"
  12.     }
  13.   ]
  14. }
复制代码
3.部门检索

  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match_all": {}
  5.   },
  6.   "sort": [
  7.     {
  8.       "account_number":  "desc"
  9.     },
  10.     {
  11.       "balance": "desc"
  12.     }
  13.   ],
  14.   "from": 0,
  15.   "size": 20,
  16.   "_source": ["balance","account_number"]
  17.   
  18. }
复制代码
4. match[匹配查询]

  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "account_number": 20
  6.     }
  7.   }
  8.   
  9. }
复制代码
  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "address": "mill lane"
  6.     }
  7.   }
  8.   
  9. }
复制代码
全文检索按照评分进行排序
5.match_phrase [短语匹配]

将必要匹配的值当成一个整体单词(不分词)进行检索
  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match_phrase": {
  5.       "address": "mill lane"
  6.     }
  7.   }
  8.   
  9. }
复制代码
6.multi_match [多字段匹配]

这是或,只要一个字段满意,就返回
  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "multi_match": {
  5.       "query": "mill",
  6.       "fields": ["state","address"]
  7.     }
  8.   }
  9.   
  10. }
复制代码
能够正常分词 
  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "multi_match": {
  5.       "query": "mill Movico",
  6.       "fields": ["city","address"]
  7.     }
  8.   }
  9.   
  10. }
复制代码
7.bool复杂查询

bool用来做复杂查询:
复合语句可以合并 任何 其他查询语句,包括复合语句,了解这一点是很紧张的。这就意味着,复合语句之间可以相互嵌套,可以表达非常复杂的逻辑。
must: 必须到达must列举所有条件 也就是相当于 AND

must_not: 且不满意里面的条件

should: 不是or 就是匹配上面有加分项

  1. GET /bank/_search
  2. {
  3.   
  4.   "query": {
  5.     "bool": {
  6.       "must": [
  7.         {
  8.           "match": {
  9.             "gender": "m"
  10.           }
  11.         },
  12.         {
  13.           "match": {
  14.             "address": "Mill"
  15.           }
  16.         }
  17.       ],
  18.       "must_not": [
  19.         {
  20.           "match": {
  21.             "age": 28
  22.           }
  23.         }
  24.       ],
  25.       "should": [
  26.         {
  27.           "match": {
  28.             "lastname": "v"
  29.           }
  30.         }
  31.       ]
  32.       
  33.       
  34.     }
  35.   }
  36.   
  37.   
  38. }
复制代码
8.filter [效果过滤]

并不是所有的查询都必要产生分数,特别是那些仅用于 "filtering" (过滤) 的文档。为了不计算分数Elasticsearch 会主动检查场景而且优化查询的执行。
  1. GET /bank/_search
  2. {
  3.   
  4.   "query": {
  5.     "bool": {
  6.       "must": [
  7.         {
  8.           "match": {
  9.             "gender": "m"
  10.           }
  11.         },
  12.         {
  13.           "match": {
  14.             "address": "Mill"
  15.           }
  16.         }
  17.       ],
  18.       "must_not": [
  19.         {
  20.           "match": {
  21.             "age": 18
  22.           }
  23.         }
  24.       ],
  25.       "should": [
  26.         {
  27.           "match": {
  28.             "lastname": "Wallace"
  29.           }
  30.         }
  31.       ],
  32.       "filter": {
  33.         "range": {
  34.           "age": {
  35.             "gte": 18,
  36.             "lte": 20
  37.           }
  38.         }
  39.       }
  40.     }
  41.   }
  42. }
复制代码
9.term

和match一样。匹配某个属性的值。全文检索字段用match,其他非text 字段匹配用term
不用全文检索的时候用term 好比数字 年岁
  1. GET /bank/_search
  2. {
  3. "query": {
  4.   "term": {
  5.     "age": {
  6.       "value": "28"
  7.     }
  8.   }
  9. }
  10. }
复制代码
  1. GET /bank/_search
  2. {
  3. "query": {
  4.   "match": {
  5.     "email.keyword": "margueritewall@aquoavo.com"
  6.   }
  7. }
  8. }
复制代码
address.keyword 和 match_phrase 区别:
前者 就是精确匹配 ,后者包含这个短语 就行

非文本字段 用 term
文本字段用 match
10. aggregations (执行聚合)

聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致即是 SQL GROUP BY 和 SQL 的聚合函数 。在Elasticsearch 中, 您有执行搜索返回 hits (命中效果) ,而且同时返回聚合效果,把一个响应中的所有hits (命中效果) 分隔开的能力 。 这黑白常强大且有效,您可以执行查询和多个聚合,而且在一次使用中得到各自 的(任何一个的) 返回效果,使用一次简化和简化的API 来制止网络往返。
搜索 address 中包含mill 的所有人的年岁分布以及平均年岁,但不显示这些人的详情。
  1. GET /bank/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "address": "mill"
  6.     }
  7.   },
  8.   "aggs": {
  9.     "ageAgg": {
  10.       "terms": {
  11.         "field": "age",
  12.         "size": 10
  13.       }
  14.     },
  15.     "ageAvg":{
  16.     "avg": {
  17.       "field": "age"
  18.     }
  19.     },
  20.     "blanceAvg":{
  21.       "avg": {
  22.         "field": "balance"
  23.       }
  24.     }
  25.   },
  26.   "size": 0
  27. }
复制代码
复杂:
按照年岁聚合,而且请求这些年岁段的这些人的平均薪资
  1. ##按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
  2. GET /bank/_search
  3. {
  4.   "query": {
  5.     "match_all": {}
  6.   },
  7.   "aggs": {
  8.     "aggAgg": {
  9.       "terms": {
  10.         "field": "age",
  11.         "size": 100
  12.       },
  13.       "aggs": {
  14.         "aggAvg": {
  15.           "avg": {
  16.             "field": "balance"
  17.           }
  18.         }
  19.       }
  20.     }
  21.   }
  22.   
  23.   
  24. }
复制代码
复杂2:
查出所有年岁分布,而且这些年岁段中M的平均薪资和F的平均薪资以及这个年岁段的总体平均薪资.
  1. ##查出所有年龄分布,并且这些年龄段中M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
  2. GET /bank/_search
  3. {
  4.   "query": {
  5.     "match_all": {}
  6.   },
  7.   "aggs": {
  8.     "aggAggs": {
  9.       "terms": {
  10.         "field": "age",
  11.         "size": 100
  12.       }
  13.       ,
  14.     "aggs": {
  15.       "avgBalanceAll":{
  16.         "avg": {
  17.         "field": "balance"
  18.       }
  19.       }
  20.       ,
  21.        "genderAgg": {
  22.           "terms": {
  23.             "field": "gender.keyword",
  24.             "size": 2
  25.           },
  26.           "aggs": {
  27.             "avgBlance": {
  28.               "avg": {
  29.                 "field": "balance"
  30.               }
  31.             }
  32.           }
  33.         }
  34.     }
  35.     }
  36.   }
  37. }
复制代码
11.mapping(映射)

所有数据类型

创建一个有类型定义的索引

  1. PUT /my_index
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "age":{"type": "integer"  },
  6.       "email":{"type": "keyword"},
  7.       "name":{"type": "text"}
  8.     }
  9.   }
  10. }
复制代码
 添加映射字段

  1. PUT /my_index/_mapping
  2. {
  3.   
  4.   "properties": {
  5.       "employee-id":{
  6.         "type":"keyword",
  7.         "index":false
  8.       }
  9.     }
  10. }
复制代码
index =false 代表不加入索引,是搜索不到他的,相当于冗余存储字段,通过其他字段查出来
迁移数据

创建新索引
  1. PUT /newbank
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "account_number": {
  6.         "type": "long"
  7.       },
  8.       "address": {
  9.         "type": "text"
  10.       },
  11.       "age": {
  12.         "type": "integer"
  13.       },
  14.       "balance": {
  15.         "type": "long"
  16.       },
  17.       "city": {
  18.         "type": "keyword"
  19.       },
  20.       "email": {
  21.         "type": "keyword"
  22.       },
  23.       "employer": {
  24.         "type": "text",
  25.         "fields": {
  26.           "keyword": {
  27.             "type": "keyword",
  28.             "ignore_above": 256
  29.           }
  30.         }
  31.       },
  32.       "firstname": {
  33.         "type": "text"
  34.       },
  35.       "gender": {
  36.         "type": "keyword"
  37.       },
  38.       "lastname": {
  39.         "type": "text",
  40.         "fields": {
  41.           "keyword": {
  42.             "type": "keyword",
  43.             "ignore_above": 256
  44.           }
  45.         }
  46.       },
  47.       "state": {
  48.         "type": "keyword"
  49.       }
  50.     }
  51.   }
  52. }
复制代码

上面是6.0以后不用类型保存的迁移方法
下面是6.0之前
 

  1. POST _reindex
  2. {
  3.   "source": {
  4.     "index": "bank",
  5.     "type": "account"
  6.   },
  7.   "dest": {
  8.     "index": "newbank"
  9.   }
  10. }
复制代码
 5.分词


  1. POST _analyze
  2. {
  3.   "analyzer": "standard",
  4.   "text": "The 2 QUICK Brown_Foxes jumped over the lazy dog's bone."
  5. }
复制代码
 1.安装ik分词器

留意:不能用默认elastics-plugin install xx.zip 进行主动安装
进入这个网址下
Index of: analysis-ik/stable/ (infinilabs.com)
进入es 容器·内部 plugins 目次
  1. docker exec -it 容器id /bin/bash
复制代码

  1. POST _analyze
  2. {
  3.   "analyzer": "ik_smart",
  4.   "text": "我是中国人"
  5. }
  6. POST _analyze
  7. {
  8.   "analyzer": "ik_max_word",
  9.   "text": "鸡你太美"
  10. }
复制代码
 安装方法和我上一篇文章一样
ElasticSearch-CSDN博客
vagrant ssh密码登录  122集


2.自定义分词器


1.重新安装nginx

下令
在nginx文件夹下,执行
  1. docker run -p 80:80 --name nginx \
  2. -v ./html:/usr/share/nginx/html \
  3. -v ./logs:/var/log/nginx \
  4. -v ./conf:/etc/nginx  \
  5. -d nginx:1.10
复制代码
 2. 创建分词文件

/opt/nginx/html/es/fenci.txt
  1. 尚硅谷
  2. 乔碧螺
复制代码
3.在es插件,路径下找到xml文件对应的分词库路径,保存位置进行修改

"/opt/elasticearch/plugins/ik/config/IKAnalyzer.cfg.xml"
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
  3. <properties>
  4.         <comment>IK Analyzer 扩展配置</comment>
  5.         <!--用户可以在这里配置自己的扩展字典 -->
  6.         <entry key="ext_dict"></entry>
  7.          <!--用户可以在这里配置自己的扩展停止词字典-->
  8.         <entry key="ext_stopwords"></entry>
  9.         <!--用户可以在这里配置远程扩展字典 -->
  10.          <entry key="remote_ext_dict">http://虚拟机地址:80/es/fenci.txt</entry>
  11.         <!--用户可以在这里配置远程扩展停止词字典-->
  12.         <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
  13. </properties>
复制代码
4.修改以后重启restart es容器

docker restart elasticsearch

6.Elasticsearch整合Spirngboot使用

1.Elasticsearch-Rest-Client 官方 RestClient ,封装类ES操纵,API条理分明,上手简单。

终极选择Elasticsearch-Rest-Client (elasticsearch-rest-high-level-client)
  1. https://www.elastic.co/guid/en/elasticsearch/client/java-rest/current/java-rest-high.html
复制代码
  1. <!--        导入ES高阶API-->
  2.         <dependency>
  3.             <groupId>org.elasticsearch.client</groupId>
  4.             <artifactId>elasticsearch-rest-high-level-client</artifactId>
  5.             <version>${elasticsearch.version}</version>
  6.         </dependency>
复制代码
  1. package com.jmj.gulimall.search.config;
  2. import org.apache.http.HttpHost;
  3. import org.elasticsearch.client.RestClient;
  4. import org.elasticsearch.client.RestHighLevelClient;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. /**
  8. * 导入依赖
  9. * 编写配置 给容器中注入一个 RestHighLevelClient
  10. * 参照官方API 操作就可以了 https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.4/java-rest-high-getting-started-initialization.html
  11. */
  12. @Configuration
  13. public class GulimallElasticSearchConfig {
  14.     @Bean
  15.     public RestHighLevelClient esRestClient() {
  16.         RestHighLevelClient client = new RestHighLevelClient(
  17.                 RestClient.builder(
  18.                         new HttpHost("192.168.232.209", 9200, "http")));
  19.         return client;
  20.     }
  21. }
复制代码
2.RequestOption

请求选项:好比安全验证,带token 请求头
  1. package com.jmj.gulimall.search.config;
  2. import org.apache.http.HttpHost;
  3. import org.elasticsearch.client.RequestOptions;
  4. import org.elasticsearch.client.RestClient;
  5. import org.elasticsearch.client.RestHighLevelClient;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. /**
  9. * 导入依赖
  10. * 编写配置 给容器中注入一个 RestHighLevelClient
  11. * 参照官方API 操作就可以了 https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.4/java-rest-high-getting-started-initialization.html
  12. */
  13. @Configuration
  14. public class GulimallElasticSearchConfig {
  15.     public static final RequestOptions COMMON_OPTIONS;
  16.     static {
  17.         RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
  18. //        builder.addHeader("Authorization", "Bearer " + TOKEN);
  19. //        builder.setHttpAsyncResponseConsumerFactory(
  20. //                new HttpAsyncResponseConsumerFactory
  21. //                        .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
  22.         COMMON_OPTIONS = builder.build();
  23.     }
  24.     @Bean
  25.     public RestHighLevelClient esRestClient() {
  26.         RestHighLevelClient client = new RestHighLevelClient(
  27.                 RestClient.builder(
  28.                         new HttpHost("192.168.232.209", 9200, "http")));
  29.         return client;
  30.     }
  31. }
复制代码
3.Index API

第一种

 第二种

第三种

第四种

  1.    /**
  2.      * 测试存储数据到ES
  3.      * 更新也可以
  4.      */
  5.     @Test
  6.     void indexData() throws IOException {
  7.         //index索引 users
  8.         IndexRequest indexRequest = new IndexRequest("users");
  9.         //设置document id ,不设置就会默认生成
  10.         /**
  11.          * 若是同样的id重复执行,就是更新操作 乐观锁控制版本
  12.          */
  13.         indexRequest.id("1");
  14.         //1. key value  pair
  15. //        indexRequest.source("userName","zhangsan","age",18,"gender","男");
  16.         //2,JSON
  17.         User user = new User("zhangsan", "男", 18);
  18.         String json = new ObjectMapper().writeValueAsString(user);
  19.         //一秒超时时间
  20.         indexRequest.timeout(TimeValue.timeValueSeconds(1));
  21.         indexRequest.source(json, XContentType.JSON);//要保存的内容
  22.         //执行操作
  23.         IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
  24.         //提取有用的响应数据
  25.         System.out.println(index);
  26.     }
复制代码
4.查询API

  1. @Data
  2.     public static class Account{
  3.         private int account_number;
  4.         private String firstname;
  5.         private String address;
  6.         private int balance;
  7.         private String gender;
  8.         private String city;
  9.         private String employer;
  10.         private String state;
  11.         private int age;
  12.         private String email;
  13.         private String lastname;
  14.     }
  15.     /**
  16.      * search检索
  17.      */
  18.     @Test
  19.     void searchData() throws IOException {
  20.         //1、创建检索请求
  21.         SearchRequest searchRequest = new SearchRequest();
  22.         //2、指定索引
  23.         searchRequest.indices("bank");
  24.         //3、检索条件DSL
  25.         SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  26. //        sourceBuilder.query();
  27. //        sourceBuilder.from();
  28. //        sourceBuilder.size();
  29. //        sourceBuilder.aggregations();
  30. //        sourceBuilder.query(QueryBuilders.matchAllQuery());
  31.         sourceBuilder.query(QueryBuilders.matchQuery("address","mill"));
  32.         //按照年龄进行分组
  33.         TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
  34.         sourceBuilder.aggregation(ageAgg);
  35.         //计算平均薪资
  36.         AvgAggregationBuilder balanceAge = AggregationBuilders.avg("balanceAvg").field("balance");
  37.         sourceBuilder.aggregation(balanceAge);
  38.         System.out.println("检索条件:"+sourceBuilder);
  39.         searchRequest.source(sourceBuilder);
  40.         //4、执行检索
  41.         SearchResponse response = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
  42.         //5、响应 分析结果
  43. //        System.out.println(response.toString());
  44.         SearchHits hits = response.getHits();
  45.         SearchHit[] hits1 = hits.getHits();
  46.         for (SearchHit documentFields : hits1) {
  47.             String sourceAsString = documentFields.getSourceAsString();
  48.             Account account = new ObjectMapper().readValue(sourceAsString, Account.class);
  49.             System.out.println(account);
  50.         }
  51.         //获取分析数据
  52.         Aggregations aggregations = response.getAggregations();
  53.         Terms ageAgg1 = aggregations.get("ageAgg");
  54.         for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
  55.             String keyAsString = bucket.getKeyAsString();
  56.             System.out.println("年龄:"+keyAsString+"=>"+bucket.getDocCount());
  57.         }
  58.         Avg balanceAvg = aggregations.get("balanceAvg");
  59.         System.out.println("平均薪资:"+balanceAvg.getValue());
  60.     }
复制代码
7.SKU 在es种存储的模子 

其中,库存信息的标题使用了ik分词器,图片信息,品牌名,品牌id等信息均不可检索。商品的规格参数等信息以nested类型,即嵌入属性存储。相关的细节这里不再赘述。
  1. PUT product
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "skuId": {
  6.         "type": "long"
  7.       },
  8.       "spuId": {
  9.         "type": "long"
  10.       },
  11.       "skuTitle": {
  12.         "type": "text",
  13.         "analyzer": "ik_smart"
  14.       },
  15.       "skuPrice": {
  16.         "type": "keyword"
  17.       },
  18.       "skuImg": {
  19.         "type": "keyword",
  20.         "index": false,
  21.         "doc_values": false
  22.       },
  23.       "saleCount": {
  24.         "type": "long"
  25.       },
  26.       "hosStock": {
  27.         "type": "boolean"
  28.       },
  29.       "hotScore": {
  30.         "type": "long"
  31.       },
  32.       "brandId": {
  33.         "type": "long"
  34.       },
  35.       "catalogId": {
  36.         "type": "long"
  37.       },
  38.       "brandName": {
  39.         "type": "keyword",
  40.         "index": false,
  41.         "doc_values": false
  42.       },
  43.       "brandImg": {
  44.         "type": "keyword",
  45.         "index": false,
  46.         "doc_values": false
  47.       },
  48.       "catalogName": {
  49.         "type": "keyword",
  50.         "index": false,
  51.         "doc_values": false
  52.       },
  53.       "attrs": {
  54.         "type": "nested",
  55.         "properties": {
  56.           "attrId": {
  57.             "type": "long"
  58.           },
  59.           "attrName": {
  60.             "type": "keyword",
  61.             "index": false,
  62.             "doc_values": false
  63.           },
  64.           "attrValue": {
  65.             "type": "keyword"
  66.           }
  67.         }
  68.       }
  69.     }
  70.   }
  71. }
复制代码
8.ES扁平化处理

  1. PUT my_index/_doc/1
  2. {
  3.   "group":"fans",
  4.   "user":[
  5.     {
  6.       "first":"John",
  7.       "last":"Smith"
  8.     },
  9.     {
  10.       "first":"Alice",
  11.       "last":"White"
  12.     }
  13.   ]
  14. }
复制代码


  1. GET my_index/_search
  2. {
  3.   "query": {
  4.     "bool": {
  5.       "must": [
  6.         {
  7.           "match": {
  8.             "user.first": "Alice"
  9.           }
  10.         },
  11.         {
  12.           "match": {
  13.             "user.first": "Alice"
  14.           }
  15.         }
  16.       ]
  17.     }
  18.   }
  19. }
复制代码

 取消扁平化处理 

  1. PUT my_index
  2. {
  3.   "mappings": {
  4.     "properties": {
  5.       "user":{
  6.         "type": "nested"
  7.       }
  8.     }
  9.   }
  10. }
复制代码
再次查询

9. 商城上架

  1. @Override
  2.     @Transactional(rollbackFor = Exception.class)
  3.     public void up(Long spuId) {
  4.         //组装需要的数据
  5.         //1. 查出当前 spuid 对应的所有sku 信息,品牌 的名字。
  6.         List<SkuInfoEntity> skuInfoEntityList = skuInfoService.getSkusBySpuId(spuId);
  7.         //TODO 查询当前sku的所有可以用来检索的属性
  8.         List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseAttrlistforspu(spuId);
  9.         List<Long> attrIds = baseAttrs.stream().map(a -> a.getAttrId()).collect(Collectors.toList());
  10.         List<Long> searchAttrIds = attrService.selectSearchAtts(attrIds);
  11.         List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().filter(item -> searchAttrIds.contains(item.getAttrId()))
  12.                 .map(item -> {
  13.                     SkuEsModel.Attrs attrs1 = new SkuEsModel.Attrs();
  14.                     BeanUtils.copyProperties(item, attrs1);
  15.                     return attrs1;
  16.                 })
  17.                 .collect(Collectors.toList());
  18.         //TODO 发送远程调用 库存系统查询是否有库存
  19.         List<Long> skuIds = skuInfoEntityList.stream().map(s -> s.getSkuId()).distinct().collect(Collectors.toList());
  20.         List<SkuHasStockVo> skusHasStock = wareFeignService.getSkusHasStock(skuIds);
  21.         Map<Long, Boolean> stockMap = skusHasStock.stream().collect(Collectors.toMap(s -> s.getSkuId(), s -> s.getHasStock()));
  22.         //2.封装每个SKU 的信息
  23.         List<SkuEsModel> upProducts = skuInfoEntityList.stream().map(sku -> {
  24.             SkuEsModel esModel = new SkuEsModel();
  25.             BeanUtils.copyProperties(sku, esModel);
  26.             esModel.setSkuPrice(sku.getPrice());
  27.             esModel.setSkuImg(sku.getSkuDefaultImg());
  28.             Long skuId = esModel.getSkuId();
  29.             Boolean aBoolean = stockMap.get(skuId);
  30.             if (aBoolean!=null){
  31.                 esModel.setHasStock(aBoolean);
  32.             }else {
  33.                 esModel.setHasStock(false);
  34.             }
  35.             //TODO 热度评分
  36.             esModel.setHotScore(0L);
  37.             //TODO 查询品牌和分类的名字信息
  38.             BrandEntity brand = brandService.getById(esModel.getBrandId());
  39.             esModel.setBrandName(brand.getName());
  40.             esModel.setBrandImg(brand.getLogo());
  41.             CategoryEntity category = categoryService.getById(esModel.getCatalogId());
  42.             esModel.setCatalogName(category.getName());
  43.             //设置检索属性
  44.             esModel.setAttrs(attrsList);
  45.             return esModel;
  46.         }).collect(Collectors.toList());
  47.         //TODO 将数据发送给es进行保存
  48.         searchFeignService.productStatusUp(upProducts);
  49.         //TODO 修改状态
  50.         this.update(new UpdateWrapper<SpuInfoEntity>()
  51.                 .set("publish_status", ProductConstant.StatusEnum.SPU_UP.getCode())
  52.                         .set("update_taime",new Date())
  53.                 .eq("id",spuId));
  54.         //Feign调用流程
  55.         /**
  56.          * 1、构造请求数据,将对象转为json
  57.          * 2、发送请求进行执行(执行成功会解码响应数据)
  58.          * 3、执行请求会有重试机制
  59.          * //默认重试机制是关闭状态
  60.          * while(true){
  61.          *   
  62.          * }
  63.          */
  64.     }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4