当前位置: 首页 > news >正文

开源网站推广sem竞价推广

开源网站推广,sem竞价推广,怎么做一家网站,做微商好还是开网站好背景前面两篇文章介绍了 SimHash 算法流程、基于 SimHash 指纹分段的相似文本检索过程,本文来介绍具体的代码实现。IT 同行都知道,编码是最没有难度的工作,不过是把前面的流程描述翻译成代码而已。本文就来翻译一下 SimHash 算法和检索工具吧…

背景

前面两篇文章介绍了 SimHash 算法流程、基于 SimHash 指纹分段的相似文本检索过程,本文来介绍具体的代码实现。

IT 同行都知道,编码是最没有难度的工作,不过是把前面的流程描述翻译成代码而已。本文就来翻译一下 SimHash 算法和检索工具吧。

流程回顾

SimHash 算法流程:

  1. 分词:对文本进行分词,得到 N 个 词 word_1word1,word_2word2​,word_3word3​ …… word_nwordn​;
  2. 赋权重:对文本进行词频统计,为各个词设置合理的权重 weight_1weight1​,weight_2weight2​,weight_3weight3​ …… weight_nweightn​;
  3. 哈希:计算每个分词的哈希值 hash_ihashi​,得到一个定长的二进制序列,一般是 64 位,也可以是 128 位;
  4. 加权重:变换每个分词 word_iwordi​ 的 hash_ihashi​,将 1 变成正的权重值 weight_iweighti​,0 变成 -weight_i−weighti​,得到一个新的序列 weightHash_iweightHashi​;
  5. 叠加权重:对每个 weightHash_iweightHashi​ 各个位上的数值做累加,最终得到一个序列 lastHashlastHash,序列的每一位都是所有分词的权重的累加值;
  6. 降维:再将 lastHashlastHash 变换成 01 序列 simHash ,方法是:权重值大于零的位置设置为 1,小于 0 的位置设置为 0,它就是整个文本的局部哈希值,即指纹。

基于 SimHash 的相似文本检索工具流程:

  1. 计算 SimHash :对目标文本计算 SimHash 值,长度为 64 位;
  2. 拆解 SimHash 值为 4 段,每一段 16 位存入数组 hashs;
  3. 遍历数组 hashs,以该段的值为 key ,调用 RedisUtil.get(key) 判断是否有缓存记录;
  4. matchedSimHash 为空,说明没有相似记录,则缓存目标文本的 SimHash 值,检索结束;否则,继续。
  5. 遍历 matchedSimHash 列表,计算当前 SimHash 与列表中每一个 SimHash 值的汉明距离,如果找到一个小等于 3 的值,则找到相似文本,流程结束;否则,继续。
  6. 外层每一段遍历结束、内存每个匹配列表遍历结束,仍然无相似记录,说明没有相似记录,则缓存目标文本的 SimHash 值,检索结束。

类图设计

SimHash 算法的实现主要难点在于分词和赋权重,本文使用 GitHub 上的一个分词工具 word ,继承它的 TextSimilarity 来实现,功能涉及的类图:

8f435ba8c62809879a4caf3a0328ae1d.png

依赖准备

创建一个项目,pom.xml 添加两个依赖:

org.apdplat      word      1.3.1com.alibaba      fastjson      1.2.70

需要注意的是,word 这个依赖不容易下载成功,可以直接将 word.1.3.1.jar 放入项目目录,手动添加依赖。

实现代码

根据 SimHash 算法流程,实现 SimHashBaseOnWord 这个类的代码如下:

public class SimHashBaseOnWord extends TextSimilarity {    private static final Logger LOGGER = LoggerFactory.getLogger(SimHashBaseOnWord.class);    // 生成 64 位的 SimHash    private int hashBitCount = 64;    public SimHashBaseOnWord(){    }    public SimHashBaseOnWord(int hashBitCount) {        this.hashBitCount = hashBitCount;    }    @Override    protected double scoreImpl(List words1, List words2){        //用词频来标注词的权重        taggingWeightWithWordFrequency(words1, words2);        //计算SimHash        String simHash1 = simHash(words1);        String simHash2 = simHash(words2);        //计算SimHash值之间的汉明距离        int hammingDistance = hammingDistance(simHash1, simHash2);        if(hammingDistance == -1){            LOGGER.error("文本1和文本2的SimHash值长度不相等,不能计算汉明距离");            return 0.0;        }        int maxDistance = simHash1.length();        double score = (1 - hammingDistance / (double)maxDistance);        return score;    }    /**     * 计算文本对应的 SimHash 值     * @param text     * @return     */    public String simHash(String text) {        List words = seg(text);        return this.simHash(words);    }    /**     * 计算等长的SimHash值的汉明距离     * 如不能比较距离(比较的两段文本长度不相等),则返回 64     * @param simHash1 SimHash值1     * @param simHash2 SimHash值2     * @return 汉明距离     */    public int hammingDistance(String simHash1, String simHash2) {        if (simHash1.length() != simHash2.length()) {            return this.hashBitCount;        }        int distance = 0;        int len = simHash1.length();        for (int i = 0; i < len; i++) {            if (simHash1.charAt(i) != simHash2.charAt(i)) {                distance++;            }        }        return distance;    }    /**     * 计算词列表的SimHash值,通过分词的时候已经统计了词的权重     * @param words 词列表     * @return SimHash值     */    private String simHash(List words) {        float[] hashBit = new float[hashBitCount];        words.forEach(word -> {            float weight = word.getWeight()==null?1:word.getWeight();            BigInteger hash = hash(word.getText());            for (int i = 0; i < hashBitCount; i++) {                BigInteger bitMask = new BigInteger("1").shiftLeft(i);                if (hash.and(bitMask).signum() != 0) {                    hashBit[i] += weight;                } else {                    hashBit[i] -= weight;                }            }        });        StringBuffer fingerprint = new StringBuffer();        for (int i = 0; i < hashBitCount; i++) {            if (hashBit[i] >= 0) {                fingerprint.append("1");            }else{                fingerprint.append("0");            }        }        return fingerprint.toString();    }    /**     * 计算文本的哈希值,很常见的一个 Hash 算法     * @param word 词     * @return 哈希值     */    private BigInteger hash(String word) {        if (word == null || word.length() == 0) {            return new BigInteger("0");        }        char[] charArray = word.toCharArray();        BigInteger x = BigInteger.valueOf(((long) charArray[0]) << 7);        BigInteger m = new BigInteger("1000003");        BigInteger mask = new BigInteger("2").pow(hashBitCount).subtract(new BigInteger("1"));        long sum = 0;        for (char c : charArray) {            sum += c;        }        x = x.multiply(m).xor(BigInteger.valueOf(sum)).and(mask);        x = x.xor(new BigInteger(String.valueOf(word.length())));        if (x.equals(new BigInteger("-1"))) {            x = new BigInteger("-2");        }        return x;    }    /**     * 对文本进行分词     * @param text     * @return     */    private List seg(String text) {        if(text == null){            return Collections.emptyList();        }        Segmentation segmentation  = SegmentationFactory.getSegmentation(SegmentationAlgorithm.MaxNgramScore);        List words = segmentation.seg(text);        if(filterStopWord) {            //停用词过滤            StopWord.filterStopWords(words);        }        return words;    }public static void main(String[] args) throws Exception{        String text1 = "我的兴趣爱好是看书";        String text2 = "看书是我的兴趣爱好";        String text3 = "我爱好看书";        SimHashBaseOnWord textSimilarity = new SimHashBaseOnWord();        double score1pk2 = textSimilarity.similarScore(text1, text2);        double score1pk3 = textSimilarity.similarScore(text1, text3);        double score2pk3 = textSimilarity.similarScore(text2, text3);        String sim1 = textSimilarity.simHash("我的兴趣爱好是看书");        String sim2 = textSimilarity.simHash("看书是我的兴趣爱好");        LOGGER.info("我的兴趣爱好是看书"+"和看书是我的兴趣爱好的汉明距离是:"+textSimilarity.hammingDistance(sim1,sim2));        System.out.println(text1+" 和 "+text2+" 的相似度分值:"+score1pk2);        System.out.println(text1+" 和 "+text3+" 的相似度分值:"+score1pk3);        System.out.println(text2+" 和 "+text3+" 的相似度分值:"+score2pk3);    }}

运行结果, “我的兴趣爱好是看书” 和 “看书是我的兴趣爱好” 的汉明距离是 0 :

6fff32efa2ab17701d672521f2cd4b5e.png

检索工具

基于 SimHashBaseOnWord 类实现的检索工具类 SearchBaseOnSimHash 的完整代码:

public class SearchBaseOnSimHash {    // 常量定义:数据库中相似记录的 id    public static final String idKey = "id";    // 常量定义:数据库中相似记录的 simHash 指纹    public static final String fingerKey = "finger";    // 日志记录类    private static final Logger LOGGER = LoggerFactory.getLogger(SearchBaseOnSimHash.class);    // 相似的汉明距离阀值    private static int similarityThreshold = 3;    /**     * 根据 SimHash 值检索文本相似的记录编号,算法流程:     *  1、将 SimHash 分成四段,以每一段为 Key 在 全局表中查找当前段的完整指纹     *  2、如果当前 SimHash 匹配到了缓冲中某一段的信息,则计算改匹配段的指纹和当前指纹的距离     *  3、如果距离小于相似度阀门值,则视为找到,返回对象;     *  4、否则,视为无相似记录     * @param segments 分段     * @param simHash     * @return     */    public static JSONObject search(String [] segments , String simHash) {        if(segments == null || segments.length != 4) {            return null;        }        // 创建一个 SimHash 对象,用于计算汉明距离        SimHashBaseOnWord simHashByWord = new SimHashBaseOnWord();        // 逐段遍历,查找计算文本相似的记录        long start = System.currentTimeMillis();        for (int i= 0; i hashSets = RedisUtil.get(segments[i]);            if(hashSets == null) {                continue;            }            // 匹配到某一段,则计算汉明距离            String finger = hashSets.get(fingerKey);            int hammingDistance = simHashByWord.hammingDistance(finger, simHash);            if (hammingDistance <= similarityThreshold){                long end = System.currentTimeMillis();                JSONObject responseObj = new JSONObject();                responseObj.put(idKey, hashSets.get(idKey));                return responseObj;            }        }        return null;    }    /**     * 向索引中添加一个 SimHash 的记录,分段遍历,将各个段加入缓存     * @param segments 分段,因为分段信息在 search 和 push 是都会用到,为了避免重复操作,作为参数     * @param simHash     * @param data     */    public static void push(String[] segments,String simHash, JSONObject data) {        if(segments == null || segments.length != 4) {            return;        }        Map redisData = new HashMap<>();        redisData.put(fingerKey, simHash);        redisData.put(idKey, data.getString(idKey));        for (int i= 0; i

启示录

理论上,基于 SimHash 的文本相似度对于越长的文本,计算结果才会越精确,但是用 wrod 分词实现的算法,长文本和短文本都比较准确,为什么呢?

分析它的启动日志:

baa6733d1d9456c7a850c888b3e7440d.png

起始加载

3f7f96051f7e1c6ed70b17b0ef7ee937.png

词数

32ba86879e41c7632143036d2f8f3c13.png

检索统计

可以得知一二:

  1. 资源词数量大;
  2. 分词过程中自动进行词频统计、自动计算权重;
  3. 属于“重量级”的工具,计算耗时相对其他分词工具,会长一些。
http://www.lbrq.cn/news/2582803.html

相关文章:

  • 做网站需要美工吗百度站长官网
  • 竞价网站制作怎样进入12345的公众号
  • 深圳找网站建设亚马逊跨境电商个人开店
  • 网站建设百度客服电话天津网站制作系统
  • 网站费做进什么科目seo搜索排名优化公司
  • 网站建设管理分工竞价广告点击软件
  • 个人网站备案名称大全成都疫情最新情况
  • 山东网站建设推广关联词有哪些关系
  • 漯河网站建设 千弘网络信息流优化师是什么
  • 网站制作上海市关键词搜索趋势
  • 网站技术有哪些搜索热门关键词
  • 最好的网页设计网站宁波seo在线优化
  • 莱芜有需要制作网站的公司吗免费b站推广网站2022
  • 新加坡的网站域名上海关键词自动排名
  • 河南春辉建设集团官方网站手机百度seo怎么优化
  • 网站设计O2O平台佛山总代理东莞网络推广策略
  • 淮安做网站找哪家公司关键词快速上首页排名
  • 太原网站建设谁家好网络销售怎么样
  • 直播网站开发核心技术seo网络优化专员
  • 玩具网站建设策划书神马推广
  • 山东网站建设好不好友情链接的形式
  • 江西个人网站备案做论坛沈阳cms模板建站
  • 事业单位网站开发工作规程高级seo培训
  • 网站建设需要些什么软件seo推广排名平台有哪些
  • wordpress分页404seo免费优化公司推荐
  • 浦东新区做网站公司关键词规划师
  • 驻马店做网站网页设计图片
  • 网络专业的网站建设武汉seo推广
  • 做网站的语言叫什么厦门百度代理
  • 创建网站的三种方法海外网络专线
  • HCIE-Datacom题库_07_设备【道题】
  • 二叉树算法之【前序遍历】
  • 兴达餐饮 酒店 进销存管理系统软件
  • 数字化转型驱动中小制造企业的质量管理升级
  • hcip---ospf知识点总结及实验配置
  • 常见框架漏洞