node.js分词搜索

背景 

最近有个需求是要实现类似【搜索引擎】的功能,用户输入关键字,后台实时推送相关数据。

思路

先仿Elasticsearch做一个简单的分词效果,然后根据分词逐一数据库查询,然后以结果【出现次数由多到少】的顺序展示数据。

实现 

第一步,做一个分词工具,区分中文英文数字,并排除特殊字符和空格(以你们实际需求修改即可),

效果如下: 

let info = "【市场价2532】HUAWEI WATCH 2 Pro 4G智能手表 移动支付"

// 分词结果:市|场|价|2532|huawei|watch|2|pro|4g|智|能|手|表|移|动|支|付

代码如下,相应注释都在其中,可直接使用: 

@/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
}

 第二步、在数据库中更具分词数组,逐一搜索,并根据结果出现次数排序

// 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
      }))
    }
  })
}

效果图: 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值