[乐优商城学习记录]DAY11 Elasticsearch入门

    技术2022-07-12  83

    参考

    https://zhuanlan.zhihu.com/learn4fun 安装步骤

    docker pull elasticsearch:6.8.8

    docker run -d --restart=always --privileged=true -v /root/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins -e “ES_JAVA_OPTS=-Xms256m -Xmx256m” --name elasticsearch -p 9200:9200 -p 9300:9300 -e “discovery.type=single-node” elasticsearch:6.8.8

    docker exec -it elasticsearch /bin/bash

    vi config/elasticsearch.yml

    cluster.name: "elasticsearch" network.host: 0.0.0.0 http.cors.enabled: true http.cors.allow-origin: "*"

    exit docker restart elasticsearch

    安装Kibana(基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等) 安装ElasticSearch Head 安装IK分词器

    基础语法 1索引 1.1创建索引 1.2查看单个索引 1.3查看所有索引 1.4删除索引 2映射 2.1创建映射字段 2.1.1type

    string(text keyword)数字 2.1.2index 2.1.3store 2.1.4boost

    2.2查看映射关系 3数据 3.1插入数据 指定id 随机id 3.2修改数据 3.3删除数据 索引就类似建表 映射就类似一些字段约束 添加数据 就类似插入一行 4查询 4.1查询所有 4.2匹配查询(单字段) match`类型查询,默认会把查询条件进行分词,然后进行查询,多个词条之间是or的关系 “operator”: “and” 可以改成and关系 介于二者之间的"minimum_should_match": “75%” 4.3多字段查询(multi_match) 在2个字段之间查找 4.4词条匹配(term) 4.5多词条精确匹配(terms) 5结果过滤 5.1 指定返回的字段 5.2 包含 或者排除 6高级查询 6.1布尔组合 must must_not should 6.2范围查询(range) 6.3模糊查询(fuzzy) 7过滤 查询会有评分,先查询好,确定好评分,然后再过滤 8排序

    聚合aggregations

    聚合,包含多种类型,最常用的两种,一个叫桶,一个叫度量

    1桶

    桶的作用,是按照某种方式对数据进行分组 每一组数据在ES中称为一个桶,例如我们根据国籍对人划分,可以得到中国桶、英国桶,日本桶……或者我们按照年龄段对人进行划分:0-10,10-20,20-30,30-40等 桶的定义,某组具有共同特征的数据 划分桶的方式: 日期阶梯分组 数值阶梯分组 根据词条内容分组 group by 数值和日期的范围分组 桶只负责对数据进行分组,并不进行计算 bucket中往往会嵌套另一种聚合:metrics aggregations即度量

    2度量

    分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量 注意事项:在ES中,需要进行聚合、排序、过滤的字段其处理方式比较特殊,因此不能被分词…字段设置为keyword类型,这个类型不会被分词,将来就可以参与聚合

    3聚合为桶

    GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" } } } }

    4桶内度量

    GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" }, "aggs":{ "avg_price": { "avg": { "field": "price" } } } } } }

    5桶内嵌套桶

    GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" }, "aggs":{ "avg_price": { "avg": { "field": "price" } }, "maker":{ "terms":{ "field":"make" } } } } } }

    6阶梯分桶Histogram

    GET /cars/_search { "size":0, "aggs":{ "price":{ "histogram": { "field": "price", "interval": 5000 } } } }

    Spring Data Elasticsearch

    Spring Data通过注解来声明字段的映射属性,有下面的三个注解:

    @Document 作用在类,标记实体类为文档对象,一般有四个属性 indexName:对应索引库名称type:对应在索引库中的类型shards:分片数量,默认5replicas:副本数量,默认1 @Id 作用在成员变量,标记一个字段作为id主键@Field 作用在成员变量,标记为文档的字段,并指定字段映射属性: type:字段类型,取值是枚举:FieldTypeindex:是否索引,布尔类型,默认是truestore:是否存储,布尔类型,默认是falseanalyzer:分词器名称:ik_max_word

    示例:

    @Document(indexName = "item",type = "docs", shards = 1, replicas = 0) public class Item { @Id private Long id; @Field(type = FieldType.Text, analyzer = "ik_max_word") private String title; //标题 @Field(type = FieldType.Keyword) private String category;// 分类 @Field(type = FieldType.Keyword) private String brand; // 品牌 @Field(type = FieldType.Double) private Double price; // 价格 @Field(index = false, type = FieldType.Keyword) private String images; // 图片地址 }

    代码示例

    @Autowired private ElasticsearchTemplate elasticsearchTemplate; @Test public void testCreate(){ // 创建索引,会根据Item类的@Document注解信息来创建 elasticsearchTemplate.createIndex(Item.class); // 配置映射,会根据Item类中的id、Field等字段来自动完成映射 elasticsearchTemplate.putMapping(Item.class); //删除索引 elasticsearchTemplate.deleteIndex("heima");

    写接口 实现行的增删改查

    public interface ItemRepository extends ElasticsearchRepository<Item,Long> { }

    用法类似jpa

    高级查询

    1 基本查询

    // 词条查询 MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米"); // 执行查询 Iterable<Item> items = this.itemRepository.search(queryBuilder); items.forEach(System.out::println);

    2 自定义查询

    // 构建查询条件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分词查询 queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米")); // 执行搜索,获取结果 Page<Item> items = this.itemRepository.search(queryBuilder.build()); // 打印总条数 System.out.println(items.getTotalElements()); // 打印总页数 System.out.println(items.getTotalPages()); items.forEach(System.out::println);

    3 分页查询

    // 构建查询条件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分词查询 queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机")); // 初始化分页参数 int page = 0; int size = 3; // 设置分页参数 queryBuilder.withPageable(PageRequest.of(page, size)); // 执行搜索,获取结果 Page<Item> items = this.itemRepository.search(queryBuilder.build()); // 打印总条数 System.out.println(items.getTotalElements()); // 打印总页数 System.out.println(items.getTotalPages()); // 每页大小 System.out.println(items.getSize()); // 当前页 System.out.println(items.getNumber()); items.forEach(System.out::println);

    4 排序

    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分词查询 queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机")); // 排序 queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC)); // 执行搜索,获取结果 Page<Item> items = this.itemRepository.search(queryBuilder.build()); // 打印总条数 System.out.println(items.getTotalElements()); items.forEach(System.out::println);

    聚合

    1 聚合为桶

    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 不查询任何结果 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null)); // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand queryBuilder.addAggregation(AggregationBuilders.terms("brands").field("brand")); // 2、查询,需要把结果强转为AggregatedPage类型 AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build()); // 3、解析 // 3.1、从结果中取出名为brands的那个聚合, // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型 StringTerms agg = (StringTerms) aggPage.getAggregation("brands"); // 3.2、获取桶 List<StringTerms.Bucket> buckets = agg.getBuckets(); // 3.3、遍历 for (StringTerms.Bucket bucket : buckets) { // 3.4、获取桶中的key,即品牌名称 System.out.println(bucket.getKeyAsString()); // 3.5、获取桶中的文档数量 System.out.println(bucket.getDocCount()); }

    2嵌套聚合,求平均值

    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 不查询任何结果 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null)); // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand queryBuilder.addAggregation( AggregationBuilders.terms("brands").field("brand") .subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶内进行嵌套聚合,求平均值 ); // 2、查询,需要把结果强转为AggregatedPage类型 AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build()); // 3、解析 // 3.1、从结果中取出名为brands的那个聚合, // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型 StringTerms agg = (StringTerms) aggPage.getAggregation("brands"); // 3.2、获取桶 List<StringTerms.Bucket> buckets = agg.getBuckets(); // 3.3、遍历 for (StringTerms.Bucket bucket : buckets) { // 3.4、获取桶中的key,即品牌名称 3.5、获取桶中的文档数量 System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "台"); // 3.6.获取子聚合结果: InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg"); System.out.println("平均售价:" + avg.getValue()); }
    Processed: 0.013, SQL: 9