博主简介:历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
热搜词是在一定时间范围内,用户搜索频率较高的词汇。在网站中,通过统计用户搜索行为来确定哪些词是热门搜索词。
在现代网站中,热搜词功能是提升用户体验和搜索效率的重要组成部分。通过实时分析用户的搜索行为,我们可以为用户提供最热门的搜索关键词,并计算每个关键词的热度,以数值形式展示。本文将详细介绍如何使用 Spring Boot 整合 Elasticsearch(ES)来实现网站的热搜词功能,并计算每个热搜词的热度。
热搜词的计算通常基于以下几个指标:
Elasticsearch(ES)在热搜中的作用
ES 是一个分布式搜索和分析引擎,非常适合用于处理大量的文本数据搜索。它具有快速的搜索速度、分布式架构、可扩展性等优点。在热搜功能中,我们可以将用户的搜索词存储到 ES 中,通过聚合(aggregation
)功能来统计每个搜索词出现的次数,进而计算出热度。
将预处理后的搜索查询数据存储到 Elasticsearch
中,并创建相应的索引。
使用 Elasticsearch
的聚合功能来计算热搜词,按照搜索词进行分组(terms aggregation
),统计每个搜索词出现的次数,并结合时间衰减函数调整热搜词的权重,计算每个热搜词的热度。
为了提高性能,将热搜词及热度结果缓存起来,并定期更新。
使用 Spring Initializr 创建一个新的 Spring Boot 项目,并添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>
dependencies>
在 application.properties
中配置 Elasticsearch 和 Redis:
spring.elasticsearch.rest.uris=http://localhost:9200
spring.redis.host=localhost
spring.redis.port=6379
创建一个用于存储搜索日志的索引映射:
PUT /search_logs
{
"mappings": {
"properties": {
"query": {
"type": "text"
},
"timestamp": {
"type": "date"
},
"user_id": {
"type": "keyword"
},
"click_count": {
"type": "integer"
}
}
}
}
创建一个 SearchLog
实体类来表示搜索日志:
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.Date;
@Document(indexName = "search_logs") // 指定索引名称
public class SearchLog {
@Id // 指定主键
private String id;
@Field(type = FieldType.Text) // 指定字段类型为文本
private String query;
@Field(type = FieldType.Date) // 指定字段类型为日期
private Date timestamp;
@Field(type = FieldType.Keyword) // 指定字段类型为关键字
private String userId;
@Field(type = FieldType.Integer) // 指定字段类型为整数
private int clickCount;
// Getters and Setters
}
创建一个 SearchLogRepository
接口来操作 Elasticsearch:
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface SearchLogRepository extends ElasticsearchRepository<SearchLog, String> {
// 继承 ElasticsearchRepository,提供基本的 CRUD 操作
}
创建一个服务类 HotSearchService
来计算热搜词及热度:
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class HotSearchService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
public List<HotSearchResult> getHotSearches() {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchAllQuery()) // 匹配所有文档
.addAggregation(AggregationBuilders.terms("hot_searches") // 添加聚合,计算热搜词
.field("query.keyword") // 聚合字段为 query 的关键字形式
.size(10) // 返回前 10 个热搜词
.order(Terms.Order.count(false)) // 按搜索次数降序排列
.subAggregation(AggregationBuilders.sum("click_sum") // 子聚合,计算点击总数
.field("click_count"))) // 聚合字段为 click_count
.withPageable(PageRequest.of(0, 10)); // 分页查询,每页 10 条记录
SearchHits<SearchLog> searchHits = elasticsearchTemplate.search(queryBuilder.build(), SearchLog.class);
Terms hotSearches = searchHits.getAggregations().get("hot_searches");
return hotSearches.getBuckets().stream()
.map(bucket -> {
String query = bucket.getKeyAsString(); // 获取热搜词
long count = bucket.getDocCount(); // 获取搜索次数
Sum clickSum = bucket.getAggregations().get("click_sum"); // 获取点击总数
double clickCount = clickSum.getValue(); // 获取点击总数
double score = count + clickCount; // 热度计算公式
return new HotSearchResult(query, score); // 返回热搜词及热度
})
.collect(Collectors.toList());
}
}
class HotSearchResult {
private String query;
private double score;
public HotSearchResult(String query, double score) {
this.query = query;
this.score = score;
}
// Getters and Setters
}
使用 Redis 缓存热搜词及热度结果,并定期更新:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class HotSearchCacheUpdater {
@Autowired
private HotSearchService hotSearchService;
@Autowired
private StringRedisTemplate redisTemplate;
@Scheduled(fixedRate = 60000) // 每分钟更新一次
public void updateHotSearches() {
List<HotSearchResult> hotSearches = hotSearchService.getHotSearches();
String hotSearchesJson = hotSearches.stream()
.map(result -> result.getQuery() + ":" + result.getScore()) // 将热搜词及热度转换为字符串
.collect(Collectors.joining(",")); // 用逗号分隔
redisTemplate.opsForValue().set("hot_searches", hotSearchesJson); // 将结果存入 Redis
}
}
创建一个控制器 HotSearchController
来提供热搜词及热度接口:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@RestController
public class HotSearchController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/hot-searches")
public List<HotSearchResult> getHotSearches() {
String hotSearchesJson = redisTemplate.opsForValue().get("hot_searches"); // 从 Redis 获取热搜词及热度
return Arrays.stream(hotSearchesJson.split(",")) // 按逗号分割
.map(entry -> {
String[] parts = entry.split(":"); // 按冒号分割
return new HotSearchResult(parts[0], Double.parseDouble(parts[1])); // 返回热搜词及热度
})
.collect(Collectors.toList());
}
}
启动 Spring Boot 应用,并访问 http://localhost:8080/hot-searches
接口,即可获取当前的热搜词列表及每个热搜词的热度。
通过 Spring Boot 整合 Elasticsearch,我们可以轻松实现网站的热搜词功能,并计算每个热搜词的热度。本文详细介绍了热搜词的原理、设计思路以及实现步骤,并提供了完整的代码示例。希望这篇文章能帮助你理解和实现热搜词及热度计算功能。
希望这篇文章能帮助你理解和实现热搜词及热度计算功能!