搜索系统 基础教程

搜索 query 分析

搜索系统 索引教程

搜索系统 高级教程

搜索系统 排序层

搜索系统 笔记

java 实现搜索系统人工干预排序的防霸屏打散

搜索系统 排序的人工干预 搜索系统 排序的人工干预


搜索系统中的打散干预,是针对内容生产者进行指定步长的阈值分开,防止同一个作者生产的内容霸屏,影响用户体验;一般该操作是在精排之后的最后一步进行微调。

java 打散实现

这里主要用一个 ArrayList 来接收已经固定的 item 数据,另一个待验证步长内重复作者的精排层结果的链表结构,这里用 LinkedHashMap,具体代码如下:

    //  同一个作者打散间距
    int gap = 3;

    //  1、待入队的 ArrayList、待检验的 LinkedHashMap
    List<ItemVO> checkedList = Lists.newArrayListWithExpectedSize(itemVOList.size());
    LinkedHashMap<Long, ItemVO> checkingMap = new LinkedHashMap<>();
    for (ItemVO itemVO : itemVOList) {
        if (itemVO...) {//  一些强行的逻辑,无需检验
            checkedList.add(itemVO);
            continue;
        }
        checkingMap.put(itemVO.getItemId(), itemVO);
    }

    //  2、待检验的 LinkedHashMap 比较前 gap 的作者信息,判断是否可以入队还是继续遍历
    int pageSize = param.getPageSize();
    boolean checkingFinish = false;//  checking 结束标识
    while (!checkingMap.isEmpty() && !checkingFinish) {
        if (checkedList.size() >= pageSize) {// 已经够数
            for (Map.Entry<Long, ItemVO> entry : checkingMap.entrySet()) {
                checkedList.add(entry.getValue());
            }
            checkingFinish = true;
        } else {
            long migrateId = 0L;//  可入队的 item id
            for (Map.Entry<Long, ItemVO> entry : checkingMap.entrySet()) {
                ItemVO itemVO = entry.getValue();
                long uid = itemVO.getUid();
                if (uid <= 0) {
                    migrateId = entry.getKey();
                    break;
                }
                //  checkedList 若空,直接插入
                if (checkedList.isEmpty()) {
                    migrateId = entry.getKey();
                    break;
                }
                //  check gap 的 authorId
                boolean existsAuthor = false;//  gap 范围内作者是否存在
                int lastIndex = checkedList.size() - 1;
                for (int i = lastIndex; i >= 0 && i >= lastIndex - gap; i--) {
                    ItemVO checkedItemVO = checkedList.get(i);
                    long authorId = checkedItemVO.getUid();
                    if (authorId > 0) {
                        if (uid == authorId) {
                            existsAuthor = true;
                            break;
                        }
                    }
                }
                if (!existsAuthor) {
                    migrateId = entry.getKey();
                    break;
                }
            }
            if (migrateId > 0) {
                checkedList.add(checkingMap.remove(migrateId));
            } else {
                //  遍历完后,都是重复的,都直接插入
                for (Map.Entry<Long, ItemVoWrapper> entry : checkingMap.entrySet()) {
                    checkedList.add(entry.getValue());
                }
                checkingFinish = true;
            }
        }
    }