互联网中热门产品计算的方案

热度值计算

热度值的计算公式 (单位时间内点击次数)

hotValue= p o i n t N u m n o w T i m e − c r e a t e T i m e \frac{pointNum}{nowTime - createTime} nowTimecreateTimepointNum

p o i n t N u m pointNum pointNum 是当前时间至产品创建时间内,所产生的点击次数
n o w T i m e nowTime nowTime 是当前时间的时间戳
c r e a t e T i m e createTime createTime 是产品创建时间的时间戳

这个公式可以理解为:产品在创建那一刻到目前为止,产品单位时间内 有被点击了多少次。

为了便于理解,我们联想一下,为了体现一辆汽车的速度快不快,通过单位时间内位移即可表示。同理,为了体现这个产品是否为热门产品,通过它的单位时间内点击次数来表示。

当然了为了避免分母为0,计算公式可以加一个常数 Δ \Delta Δ计算,比如变成如下的公式。

hotValue= p o i n t N u m n o w T i m e − c r e a t e T i m e + Δ \frac{pointNum}{nowTime - createTime + \Delta} nowTimecreateTime+ΔpointNum

代码过程

在我们日常生活中,热门推荐是一个很重要的推荐,也是一个推荐系统的起步。不需要详细记录用户的信息,就可以为用户推荐热门的产品。本文从日志打印、到日志分析、最终形成推荐候选集的方面进行阐述,本文的设计热门产品计算的计算瓶颈取决于Java中的Map能存放多少条数据。

如下图是计算每个产品的流程图。
在这里插入图片描述
1 在用户端需要添加日志记录,比如以用户点击为热度指标,那么在用户点击某个产品后,则进行记录,并将日志记录在某个文件内。
2 在用户行为信息形成日志后,需要对其对日志聚合分析,形成如下的Map结构性的数据

"itemId":112233,
"pointNum": 123

key: 112233, value: 123

3 根据热度值进行计算

{
    
    
"itemId":112233,
"hotValue":0.5
}

4 数据库查找的时候,以hotValue为排序指标查找前多少位的数据,即可查找到钱多少的热门数据。

扫描二维码关注公众号,回复: 13247125 查看本文章

知道热门试题的大致步骤后,开始实现的部分,在后端中每个用户如果点击产品后,我我采用log4j2将日志打印到一个指定的文件内。

<RollingFile name="XiaotiBehaviorInfo" fileName="${LOG_PATH}/xiaotiapp/xiaoti_behavior.log"
filePattern="${LOG_PATH}/xiaotiapp/xiaoti_behavior-log-date-%d{yyyy-MM-dd}-%i.log" append="true">
	<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
	<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
	<PatternLayout pattern="${sys:FILE_LOG_PATTERN}"/>
	<Policies>
		<TimeBasedTriggeringPolicy modulate="true" interval="24"/>
		<SizeBasedTriggeringPolicy/>
	</Policies>
	<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
	<DefaultRolloverStrategy max="30"/>
</RollingFile>

<!--拦截某个方法,调用XiaotiBehaviorInfo,打印到另一个文件中-->
<logger name="com.marsdl.api.xiaotiapi.service.QuestionService" level="info" additivity="false">
<AppenderRef ref="XiaotiBehaviorInfo"/>
</logger>

配置好后端服务的日志后,日志就记录在xiaoti_behavior.log文件内,后面按行读取然后判断是否为你所想要的日志即可。如下代码检测每一行的日志中是否包含xiaotiapp-behavior-answerResult,如果包含则为我所想要的那条日志,然后记录在Map中达到聚合的目的。

public void handleLogLine(String line) {
    
    
    if (StringUtils.isBlank(line)) {
    
    
        return;
    }
    String[] itemArr = line.split("\\s\\s");
    if (StringUtils.isNotBlank(itemArr[1]) && itemArr[1].contains("xiaotiapp-behavior-answerResult")) {
    
    
        HotQuestion hotQuestion = new HotQuestion();
        for (String item : itemArr[1].trim().split("\\,")) {
    
    
            item = item.trim();
            String titleId = "0";
            if (item.startsWith("titleId:")) {
    
    
                titleId = item.split("titleId:")[1];
                hotQuestion.setTitleId(titleId);
                Long count = titleIdCountMap.get(titleId);
                if (count != null) {
    
    
                    titleIdCountMap.put(titleId, count + 1L);
                } else {
    
    
                    titleIdCountMap.put(titleId, 1L);
                }
            }
        }
    }
}

为了便于您的更好的分析,如下代码是按行读取日志文件,判断特征,聚合特征,然后计算热度值。

//指定路径按行读取
public void readLog(final String filepath) throws Exception {
    
    
    //仔细查看
    dao.dropCollection(xiaotiHotquestion);

    long nowTime = System.currentTimeMillis();
    try (
            BufferedReader reader = new BufferedReader(new FileReader(filepath));
    ) {
    
    
        String line = null;
        while ((line = reader.readLine()) != null) {
    
    
            System.out.println(line);
            handleLogLine(line);
        }
        System.out.println("");
    } catch (Exception e) {
    
    
        e.printStackTrace();
    }
    long wasteTime = System.currentTimeMillis() - nowTime;
    System.out.println("读取解析日志耗时(ms): " + wasteTime);

    for (Map.Entry<String, Long> entry : titleIdCountMap.entrySet()) {
    
    
        String titleId = entry.getKey();

        XiaotiQuestionDbResource dbResource = dao.findQuestion(titleId,
                XiaotiQuestionDbResource.class, DB_COLLECTION);

        if (dbResource == null) {
    
    
            continue;
        }

        Long answerNum = entry.getValue();
        Double answerNumDouble = answerNum.doubleValue();

        long time = System.currentTimeMillis();
        long addTime = dbResource.getAddTime();
        //时长
        long delta = Math.abs(addTime - time);
        delta = delta == 0 ? 1 : delta;

        //天数
        double days = delta / (1000 * 60 * 60 * 24);
        if (delta < (1000 * 60 * 60 * 24)) {
    
    
            days = 0.5;
        }
        //计算热度值
        double hotValue = answerNumDouble / days;
        //封装存储数据
        HotQuestion hotQuestion = new HotQuestion();
        String titleContent = dbResource.getTitleContent();
        if (titleContent.length() > 14) {
    
    
            titleContent = titleContent.substring(0, 14);
        }
        hotQuestion.setTitleContent(titleContent);
        hotQuestion.setTitleId(titleId);
        hotQuestion.setHotValue(hotValue);
        hotQuestion.setCourse(dbResource.getCourse());

        System.out.println(JSON.toJSONString(hotQuestion));
        dao.saveEntity(hotQuestion, xiaotiHotquestion);
    }

}

猜你喜欢

转载自blog.csdn.net/Hello_Ray/article/details/117001818