Elasticsearch实战(五):Springboot实现Elasticsearch电商平台日志埋点与搜索热词

news2025/1/13 13:14:45

文章目录

  • 系列文章索引
  • 一、提取热度搜索
    • 1、热搜词分析流程图
    • 2、日志埋点
      • (1)排除logback的默认集成。
      • (2)引入log4j2起步依赖
      • (3)设置配置文件
      • (4)配置文件模板
      • (5)日志埋点
      • (6)创建索引
    • 3、数据落盘(logstash)
      • (1)配置Logstash.conf
      • (2)查询是否有数据
      • (3)执行API全文检索
  • 二、热度搜索OpenAPI
    • 1、聚合
    • 2、DSL实现
    • 3、 OpenAPI查询参数设计

系列文章索引

Elasticsearch实战(一):Springboot实现Elasticsearch统一检索功能
Elasticsearch实战(二):Springboot实现Elasticsearch自动汉字、拼音补全,Springboot实现自动拼写纠错
Elasticsearch实战(三):Springboot实现Elasticsearch搜索推荐
Elasticsearch实战(四):Springboot实现Elasticsearch指标聚合与下钻分析
Elasticsearch实战(五):Springboot实现Elasticsearch电商平台日志埋点与搜索热词

一、提取热度搜索

1、热搜词分析流程图

在这里插入图片描述

2、日志埋点

整合Log4j2

相比与其他的日志系统,log4j2丢数据这种情况少;disruptor技术,在多线程环境下,性能高于logback等10倍以上;利用jdk1.5并发的特性,减少了死锁的发生;

(1)排除logback的默认集成。

因为Spring Cloud 默认集成了logback, 所以首先要排除logback的集成,在pom.xml文件

<!--排除logback的默认集成 Spring Cloud 默认集成了logback-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>

(2)引入log4j2起步依赖

<!-- 引入log4j2起步依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- log4j2依赖环形队列-->
<dependency>
	<groupId>com.lmax</groupId>
	<artifactId>disruptor</artifactId>
	<version>3.4.2</version>
</dependency>

(3)设置配置文件

如果自定义了文件名,需要在application.yml中配置
进入Nacos修改配置

logging:
	config: classpath:log4j2-dev.xml

(4)配置文件模板

<Configuration>
	<Appenders>
		<Socket name="Socket" host="172.17.0.225" port="4567">
			<JsonLayout compact="true" eventEol="true" />
		</Socket>
	</Appenders>
	<Loggers>
		<Root level="info">
			<AppenderRef ref="Socket"/>
		</Root>
	</Loggers>
</Configuration>

从配置文件中可以看到,这里使用的是Socket Appender来将日志打印的信息发送到Logstash。
注意了,Socket的Appender必须要配置到下面的Logger才能将日志输出到Logstash里!
另外这里的host是部署了Logstash服务端的地址,并且端口号要和你在Logstash里配置的一致才行。

(5)日志埋点

private void getClientConditions(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {
	//循环前端的查询条件
	for (Map.Entry<String, Object> m : commonEntity.getMap().entrySet()) {
		if (StringUtils.isNotEmpty(m.getKey()) && m.getValue() != null) {
			String key = m.getKey();
			String value = String.valueOf(m.getValue());
			//构造请求体中“query”:{}部分的内容 ,QueryBuilders静态工厂类,方便构造
			queryBuilder
			searchSourceBuilder.query(QueryBuilders.matchQuery(key, value));
			logger.info("search for the keyword:" + value);
		}
	}
}

(6)创建索引

下面的索引存储用户输入的关键字,最终通过聚合的方式处理索引数据,最终将数据放到语料库

PUT es-log/
{
    "mappings": {
        "properties": {
            "@timestamp": {
                "type": "date"
            },
            "host": {
                "type": "text"
            },
            "searchkey": {
                "type": "keyword"
            },
            "port": {
                "type": "long"
            },
            "loggerName": {
                "type": "text"
            }
        }
    }
}

3、数据落盘(logstash)

(1)配置Logstash.conf

连接logstash方式有两种
(1) 一种是Socket连接
(2)另外一种是gelf连接

input {
    tcp {
        port => 4567
        codec => json
    }
}

filter {
#如果不包含search for the keyword则删除
    if [message] =~  "^(?!.*?search for the keyword).*$" {
        drop {}
  }
     mutate{
#移除不需要的列
        remove_field => ["threadPriority","endOfBatch","level","@version","threadId","tags","loggerFqcn","thread","instant"]
#对原始数据按照:分组,取分组后的搜索关键字
  split=>["message",":"]
                add_field => {
                        "searchkey" => "%{[message][1]}"
                }
#上面新增了searchkey新列,移除老的message列
 remove_field => ["message"]
           }
 }

# 输出部分
output {
    elasticsearch {
        # elasticsearch索引名
        index => "es-log"
        # elasticsearch的ip和端口号
        hosts => ["172.188.0.88:9200","172.188.0.89:9201","172.188.0.90:9202"]
    }
    stdout {
        codec => json_lines
    }
}

重启Logstash,对外暴露4567端口:

docker run --name logstash   -p 4567:4567 -v /usr/local/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml   -v /usr/local/logstash/config/conf.d/:/usr/share/logstash/pipeline/   -v /usr/local/logstash/config/jars/mysql-connector-java-5.1.48.jar:/usr/share/logstash/logstash-core/lib/jars/mysql-connector-java-5.1.48.jar       --net czbkNetwork --ip 172.188.0.77 --privileged=true  -d  c2c1ac6b995b

(2)查询是否有数据

GET es-log/_search
{
	"from": 0,
	"size": 200,
	"query": {
		"match_all": {}
	}
}

返回:
{
	"_index" : "es-log",
	"_type" : "_doc",
	"_id" : "s4sdPHEBfG2xXcKw2Qsg",
	"_score" : 1.0,
	"_source" : {
		"searchkey" : "华为全面屏",
		"port" : 51140,
		"@timestamp" : "2023-04-02T18:18:41.085Z",
		"host" : "192.168.23.1",
		"loggerName" :
		"com.service.impl.ElasticsearchDocumentServiceImpl"
	}
}

(3)执行API全文检索

参数:

{
	"pageNumber": 1,
	"pageSize": 3,
	"indexName": "product_list_info",
	"highlight": "productname",
	"map": {
		"productname": "小米"
	}
}

二、热度搜索OpenAPI

1、聚合

获取es-log索引中的文档数据并对其进行分组,统计热搜词出现的频率,根据频率获取有效数据。

2、DSL实现

field:查询的列,keyword类型
min_doc_count:热度大于1次的
order:热度排序
size:取出前几个
per_count:"自定义聚合名

POST es-log/_search?size=0
{
    "aggs": {
        "result": {
            "terms": {
                "field": "searchkey",
                "min_doc_count": 5,
                "size": 2,
                "order": {
                    "_count": "desc"
                }
            }
        }
    }
}

结果:
{
    "took": 13,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 40,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    },
    "aggregations": {
        "per_count": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 12,
            "buckets": [
                {
                    "key": "阿迪达斯外套",
                    "doc_count": 14
                },
                {
                    "key": "华为",
                    "doc_count": 8
                }
            ]
        }
    }
}

3、 OpenAPI查询参数设计

/*
 * @Description: 获取搜索热词
 * @Method: hotwords
 * @Param: [commonEntity]
 * @Update:
 * @since: 1.0.0
 * @Return: java.util.List<java.lang.String>
 *
 */
public Map<String, Long> hotwords(CommonEntity commonEntity) throws Exception {
    //定义返回数据
    Map<String, Long> map = new LinkedHashMap<String, Long>();
    //执行查询
    SearchResponse result = getSearchResponse(commonEntity);
    //这里的自定义的分组别名(get里面)key当一个的时候为动态获取
    Terms packageAgg = result.getAggregations().get(result.getAggregations().getAsMap().entrySet().iterator().next().getKey());
    for (Terms.Bucket entry : packageAgg.getBuckets()) {
        if (entry.getKey() != null) {
            // key为分组的字段
            String key = entry.getKey().toString();
            // count为每组的条数
            Long count = entry.getDocCount();
            map.put(key, count);
        }
    }

    return map;
}
/*
 * @Description: 查询公共调用,参数模板化
 * @Method: getSearchResponse
 * @Param: [commonEntity]
 * @Update:
 * @since: 1.0.0
 * @Return: org.elasticsearch.action.search.SearchResponse
 *
 */
private SearchResponse getSearchResponse(CommonEntity commonEntity) throws Exception {
    //定义查询请求
    SearchRequest searchRequest = new SearchRequest();
    //指定去哪个索引查询
    searchRequest.indices(commonEntity.getIndexName());
    //构建资源查询构建器,主要用于拼接查询条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    //将前端的dsl查询转化为XContentParser
    XContentParser parser = SearchTools.getXContentParser(commonEntity);
    //将parser解析成功查询API
    sourceBuilder.parseXContent(parser);
    //将sourceBuilder赋给searchRequest
    searchRequest.source(sourceBuilder);
    //执行查询
    SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
    return response;
}

调用hotwords方法参数:

{
    "indexName": "es-log",
    "map": {
        "aggs": {
            "per_count": {
                "terms": {
                    "field": "searchkey",
                    "min_doc_count": 5,
                    "size": 2,
                    "order": {
                        "_count": "desc"
                    }
                }
            }
        }
    }
}

field表示需要查找的列
min_doc_count:热搜词在文档中出现的次数
size表示本次取出多少数据
order表示排序(升序or降序)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/981102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用高斯混合模型进行聚类

一、说明 高斯混合模型 &#xff08;GMM&#xff09; 是一种基于概率密度估计的聚类分析技术。它假设数据点是由具有不同均值和方差的多个高斯分布的混合生成的。它可以在某些结果中提供有效的聚类结果。 二、Kmean算法有效性 K 均值聚类算法在每个聚类的中心周围放置一个圆形边…

效果好的it监控系统特点

一个好的IT监控系统应该具备以下特点&#xff1a;  全面性&#xff1a;IT监控系统应该能够监视和管理IT系统的所有方面&#xff0c;包括网络、服务器、应用程序和数据库等。这样可以确保系统的各个方面都得到充分的监视和管理。  可靠性&#xff1a;IT监控系统需要保持高可…

docker 跨平台构建镜像

我们在开发环境构建的镜像在生产环境大多不可用&#xff0c;我们在开发中一般使用 Windows 或者 MAC 系统&#xff0c;部署多半是 linux 环境。那么这篇文章能帮到你。 文章目录 首先构建环境进阶 首先 首先你需要有一个 Dockerfile 文件。 举例&#xff1a;这里以一个 pytho…

SpringMVC之综合案例

SpringMVC注解 Controller: 标记一个类为控制器&#xff08;处理请求的类&#xff09;&#xff0c;将其作为Spring MVC的组件进行管理。 RequestMapping: 将请求URL映射到具体的处理方法上。可以用在类级别和方法级别&#xff0c;用于指定URL路径。 RequestParam: 用于将请求…

流式数据处理与高吞吐消息传递:深入探索Kafka技术的奥秘

Kafka 是一种高吞吐量、分布式、基于发布/订阅的消息系统&#xff0c;最初由 LinkedIn 公司开发&#xff0c;使用Scala 语言编写&#xff0c;目前是 Apache 的开源项目。 Kafka 概念 Zookeeper 集群是一个基于主从复制的高可用集群&#xff0c;每个服务器承担如下三种角色中的…

【网络编程】C++实现网络通信服务器程序||计算机网络课设||Linux系统编程||TCP协议(附源码)

TCP网络服务器 &#x1f40d; 1.程序简洁&#x1f98e;2. 服务端ServerTcp程序介绍&#x1f996;3.线程池ThreadPool介绍&#x1f995; 4.任务类Task介绍&#x1f419;5. 客户端Client介绍&#x1f991;6.运行结果&#xff1a;&#x1f990; 7. 源码&#x1f99e;7.1 serverTcp…

C++内存管理(3)——内存池

1. 默认内存管理函数的不足&#xff08;为什么使用内存池&#xff09; 利用默认的内存管理操作符 new/delete 和函数 malloc()/free() 在堆上分配和释放内存会有一些额外的开销。 系统在接收到分配一定大小内存的请求时&#xff0c;首先查找内部维护的内存空闲块表&#xff0…

纯css制作常见的图形

1.正方形 <div class"square"></div> .square {width: 100px;height: 100px;background-color: #ffff00;} 效果&#xff1a; 2.长方形 <div class"rectangle"></div> .rectangle{width: 200px;height: 100px;background-color:…

用huggingface.Accelerate进行分布式训练

诸神缄默不语-个人CSDN博文目录 本文属于huggingface.transformers全部文档学习笔记博文的一部分。 全文链接&#xff1a;huggingface transformers包 文档学习笔记&#xff08;持续更新ing…&#xff09; 本部分网址&#xff1a;https://huggingface.co/docs/transformers/m…

Layui快速入门之第一节Layui的基本使用

目录 一&#xff1a;Layui的基本概念 二&#xff1a;Layui使用的基本步骤 1.在官网下载layui的基本文件&#xff0c;引入css和js文件 ①&#xff1a;普通方式引入 ②&#xff1a;第三方 CDN 方式引入 2.在script标签体中编写代码 3.测试 一&#xff1a;Layui的基本概念 …

Mac m1 安装rabbitmq+php-amqplib

rabbitmq 官方地址 https://www.rabbitmq.com mac 软件包 Downloading and Installing RabbitMQ — RabbitMQ 一.这里我选择 homebrew brew updatebrew install rabbitmq二.php代码 用composer 安装 10年软件开发经验,结交朋友! 分销商城系统开发,App商城开发 商务合作 s…

eclipse进入断点之后,一直卡死,线程一直在运行【记录一种情况】

问题描述: 一直卡死在某个断点处&#xff0c;取消断点也是卡死在这边的进程处。 解决方式&#xff1a; 将JDK的使用内存进行了修改 ① 打开eclipse&#xff0c;window->preference->Java->Installed JREs&#xff0c;选中使用的jdk然后点击右侧的edit&#xff0c;在…

打造基于终端命令行的IDE,Termux配置Vim C++开发环境

Termux配置Vim C开发环境&#xff0c;打造基于终端命令行的IDE 主要利用VimCoc插件&#xff0c;配置C的代码提示等功能。 Termux换源 打开termux&#xff0c;输入termux-change-repo 找到mirrors.tuna.tsinghua.edu.cn&#xff0c;清华源&#xff0c;空格选中&#xff0c;回…

LeetCode(力扣)40. 组合总和 IIPython

LeetCode40. 组合总和 II 题目链接代码 题目链接 https://leetcode.cn/problems/combination-sum-ii/ 代码 class Solution:def backtrackingz(self, candidates, target, result, total, path, startindex):if target total:result.append(path[:])return for i in range…

elasticsearch访问9200端口 提示需要登陆

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; elasticsearch访问9200端口 提示需要登陆 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 在E:\elasticsearch-8.9.1-windows-x86_64\elasticsearch-8.9.1\bin目录下输入命令 ela…

手写Spring:第5章-注入属性和依赖对象

文章目录 一、目标&#xff1a;注入属性和依赖对象二、设计&#xff1a;注入属性和依赖对象三、实现&#xff1a;注入属性和依赖对象3.0 引入依赖3.1 工程结构3.2 注入属性和依赖对象类图3.3 定义属性值和属性集合3.3.1 定义属性值3.3.2 定义属性集合 3.4 Bean定义补全3.5 Bean…

Flutter实用工具Indexer列表索引和Search搜索帮助。

1.列表索引 效果图&#xff1a; indexer.dart import package:json_annotation/json_annotation.dart;abstract class Indexer {///用于排序的字母JsonKey(includeFromJson: false, includeToJson: false)String? sortLetter;///用于排序的拼音JsonKey(includeFromJson: fal…

学习笔记|计数器|Keil软件中 0xFD问题|I/O口配置|STC32G单片机视频开发教程(冲哥)|第十二集:计数器的作用和意义

文章目录 1.计数器的用途2.计数器的配置官方例程开始Tips&#xff1a;编译时提示错误FILE DOES NOT EXIST&#xff1a; 3.计数器的应用本例完整代码&#xff1a;总结课后练习&#xff1a; 1.计数器的用途 直流有刷的电机,后面两个一正一负的电接上,电机就可以转 到底是转子个…

NLP(六十八)使用Optimum进行模型量化

本文将会介绍如何使用HuggingFace的Optimum&#xff0c;来对微调后的BERT模型进行量化&#xff08;Quantization&#xff09;。   在文章NLP&#xff08;六十七&#xff09;BERT模型训练后动态量化&#xff08;PTDQ&#xff09;中&#xff0c;我们使用PyTorch自带的PTDQ&…

李宏毅-机器学习hw4-self-attention结构-辨别600个speaker的身份

一、慢慢分析学习pytorch中的各个模块的参数含义、使用方法、功能&#xff1a; 1.encoder编码器中的nhead参数&#xff1a; self.encoder_layer nn.TransformerEncoderLayer( d_modeld_model, dim_feedforward256, nhead2) 所以说&#xff0c;这个nhead的意思&#xff0c;就…