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