背景
最近有个需求是要实现类似【搜索引擎】的功能,用户输入关键字,后台实时推送相关数据。
思路
先仿Elasticsearch做一个简单的分词效果,然后根据分词逐一数据库查询,然后以结果【出现次数由多到少】的顺序展示数据。
实现
第一步,做一个分词工具,区分中文、英文数字,并排除特殊字符和空格(以你们实际需求修改即可),代码如下,相应注释都在其中,可直接使用
@/utils/index.js
/**
* 搜索输入分词处理
* @param info 用户输入的字符串
* @returns {*|*[]|*[]|null}
*/
function infoDeal (info) {
let list = []
// 初步判断是否输入字符
if (info === null | info === undefined) {
return undefined
} else if (info.trim() === '') {
return list
} else {
let infos = info
let list2 = []
let list3 = []
// 英文大写转小写,获得新字符串
infos = infos.toLowerCase()
// 清除空格,并依据空格分割为数组
list2 = infos.split(' ')
// 清除字符之间存在多个空格的情况
list2.forEach(item => {
if (item !== '') {
list3.push(item)
}
})
// 正则判断,区分中文、英文数字,并排除特殊字符
let isEnglish = new RegExp('[A-Za-z]+')
let isInt = new RegExp('[0-9]+')
let isSpecialChar = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>《》/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]")
// 利用正则分词,中文直接push添加到数组,英文数字整一串push进数组,特殊字符直接舍弃
list3.forEach(item => {
let isEng = false // 判断是否开始记录英文数字
let Eng = '' // 记录英文数字组合
for (let i = 0; i < item.length; i++) {
// 判断是否是英文数字
if (isEnglish.test(item[i]) | isInt.test(item[i])) {
// 判断是否开始记录了这一串英文数字组合
if (!isEng) {
Eng = item[i]
isEng = true
} else {
Eng = Eng + item[i]
}
// 判断是否是最后一个字符
if (i === item.length - 1) {
list.push(Eng)
}
} else if (isSpecialChar.test(item[i])) {
// 判断是否是特殊字符
if (Eng) {
list.push(Eng)
Eng = ''
isEng = false
}
} else {
if (Eng) {
list.push(Eng)
Eng = ''
isEng = false
}
list.push(item[i])
}
}
})
return list
}
}
module.exports = {
infoDeal
}
效果如下:
let info = "【市场价2532】HUAWEI WATCH 2 Pro 4G智能手表 移动支付"
// 分词结果:市|场|价|2532|huawei|watch|2|pro|4g|智|能|手|表|移|动|支|付
第二步、在数据库中更具分词数组,逐一搜索,并根据结果出现次数排序
// infoList就是前面分词返回的数组,这是在判断数组不为空的前提下执行的方法
function SearchCsgoskin (conn, res, infoList) {
let list = [] // 返回结果列表
let sql = ''
// 循环添加搜索语句
infoList.forEach((item, index) => {
sql = sql + 'SELECT name from csgoskin WHERE name like "%' + item + '%";'
})
conn.query(sql, (err, result, fields) => {
if (err) {
console.log(err)
res.end(JSON.stringify({
code: 301,
msg: '检索意外错误',
data: err
}))
} else {
if (result.length > 1) {
let allresult = []
let numresult = {}
// 将全部结果合并为一个数组
for (let i = 0; i < result.length; i++) {
allresult = allresult.concat(result[i])
}
// 记录出现次数
allresult.forEach(item => {
if (numresult[item.name] === undefined) {
numresult[item.name] = 1
} else {
numresult[item.name] = numresult[item.name] + 1
}
})
// 根据出现次数进行排序(纯数组)
let sortList = Object.keys(numresult).sort((a, b) => {
return numresult[b] - numresult[a]
})
// 为了适应提示框,将结果变成【对象数组】
sortList.forEach(item => {
let obj = {}
obj['name'] = item
list.push(obj)
})
} else {
list = result
}
res.end(JSON.stringify({
code: 200,
msg: '检索成功',
data: list
}))
}
})
}
效果图: