精华内容
下载资源
问答
  • 而搜索引擎的分词简单的理解,就是把搜索语句分成若干个互相独立、完整、正确的单词,然后在理解每个单词意思的基础上,根据汉语语法规则、语境、近义词,匹配出更符合用户搜索的关键词或语句的搜索结果。...

    在自然语言处理技术中,许多西文的处理方法中文不能直接采用,就是因为中文需要有分词这道工序。而搜索引擎的分词简单的理解,就是把搜索语句分成若干个互相独立、完整、正确的单词,然后在理解每个单词意思的基础上,根据汉语语法规则、语境、近义词,匹配出更符合用户搜索的关键词或语句的搜索结果。搜索引擎的分词算法特点:动态学习的过程,它会周期性基于词典、统计方法进行相关性计算和筛选。怎么理解呢?举个例子:

    从SEO角度看中文分词,在seo优化的过程中,

    8e8d986c7e86f13233245fb89b7fa0aa.png

    百度分词算法

    我们偶尔会遇到这样一种情况,那就是当我们检索某一个特定词组的时候,你会发现排名第一的网页title中,并没有包含特定的完整关键词。如果完全匹配,那就说明网页内容质量比较高,而需求词设计的精准度高。所以在做百度SEO时,我们也要注意分词,确保网页标题出现的关键词是符合大多数网民的搜索需求。

    那么如何,利用百度搜索分词算法布局关键词?通常,中文分词算法提取的信息包括:关键词,关键词的属性(名词、动词、形容词等),出现的频率,本身的权重(笔者认为类似百度指数),从按照最大匹配法、最少切分做排序。具体有4个布局技巧

    1、切分关键词

    比如:查关键词排名工具,标题包含“关键词排名查询”就比不拆分好的多

    2、利用同义词

    如搜索“文章撰写”搜索结果列表会展示“文章写作”相关标题。

    3、利用拼音关键词

    比如搜索sainitieke,就能显示企业相关的文章。

    注意,不要使用带有一些非法内容的关键词。

    最后举个例子,乳胶漆批发_提供2018乳胶漆批发团购价格-XX乳胶漆批发厂家就依次匹配乳胶漆团购、乳胶漆价格、乳胶漆批发价格、乳胶漆批发厂家等关键词,做到了最大化的匹配。如果这些关键词不分开,就会造成严重的关键词堆砌;如果只选一个做标题,匹配的词又少,所以如果你了解了分词技术,按照关键词的权重依次进行匹配,就能实现一个标题有多个关键词的排名的目标。

    展开全文
  • 我以前用过Jieba、Pkuseg、HanLP等开源工具的分词功能,现在主要通过《自然语言...中文分词指的是将一段文本拆分为一系列单词的过程,将这些单词顺序拼接后等于原文本。 中文分词算法大致分为基于词典规则和基于...

    我以前用过Jieba、Pkuseg、HanLP等开源工具的分词功能,现在主要通过《自然语言处理入门》(何晗)的第2章来学习一下分词的常用算法,因此以下的实现方法都是通过HanLP实现的。这里主要记录我在学习过程中整理的知识、调试的代码和心得理解,以供其他学习的朋友参考。

    中文分词指的是将一段文本拆分为一系列单词的过程,将这些单词顺序拼接后等于原文本。

    中文分词算法大致分为基于词典规则和基于机器学习这两大派别。词典分词是最简单、最常见的分词算法,仅需一部词典和一套查词典的规则即可。

    下面主要介绍以下4种切分算法:完全切分、正向最长匹配、逆向最长匹配、双向最长匹配。

    加载字典

    我们载入HanLP的核心词典的词语列表作为研究对象。

    from pyhanlp import HanLP
    from pyhanlp import JClass
    
    def load_dictionary():
        """
        加载HanLP中的mini词库
        :return: 一个set形式的词库
        """
        IOUtil = JClass('com.hankcs.hanlp.corpus.io.IOUtil')  # 利用HanLP提供的JClass取得HanLP中的IOUtil工具类
        path = HanLP.Config.CoreDictionaryPath.replace('.txt', '.mini.txt')  # 获取HanLP的设置项Config中的词典路径
        dic = IOUtil.loadDictionary([path])  # 调用IOUtil的静态方法loadDictionary;其返回值为一个字典对象(Java的Map对象);这个字典的key为词语,value为词语的词性和频数;因为这里我们只需要词语列表,所以使用keySet获取Set对象的词语列表。
        return set(dic.keySet())
    
    if __name__ == "__main__":
        dic = load_dictionary()
        print("词典大小:", len(dic))
        print("词典中的第1个词:", list(dic)[0])

    运行结果

    词典大小: 85584
    词典中的第1个词: 分流

    完全切分

    完全切分指的是,找出一段文本中所有单词,无论这个词在这个句子中是否是一个词。

    朴素的完全切分算法的实现逻辑,是遍历文本中所有的连续序列,并查询该序列是否存在于词典中。

    import load_dictionary # 载入加载词典的函数
    
    def fully_segment(text, dic):
        word_list = []
        for i in range(len(text)):  # 遍历text中的所有位置下标
            for j in range(i + 1, len(text) + 1):  # 遍历[i + 1, len(text)]区间
                word = text[i:j]  # 取出连续区间[i, j]对应的字符串
                if word in dic:  # 如果存在于词典中,则认为是一个词
                    word_list.append(word)
        return word_list
    
    if __name__ == '__main__':
        dic = load_dictionary()
        print(fully_segment('项目的研究', dic))
        print(fully_segment('商品和服务', dic))
        print(fully_segment('研究生命起源', dic))
        print(fully_segment('当下雨天地面积水', dic))
        print(fully_segment('结婚的和尚未结婚的', dic))
        print(fully_segment('欢迎新老师生前来就餐', dic))

    运行结果

    ['项', '项目', '目', '目的', '的', '研', '研究', '究']
    ['商', '商品', '品', '和', '和服', '服', '服务', '务']
    ['研', '研究', '研究生', '究', '生', '生命', '命', '起', '起源', '源']
    ['当', '当下', '下', '下雨', '下雨天', '雨', '雨天', '天', '天地', '地', '地面', '面', '面积', '积', '积水', '水']
    ['结', '结婚', '婚', '的', '和', '和尚', '尚', '尚未', '未', '结', '结婚', '婚', '的']
    ['欢', '欢迎', '迎', '迎新', '新', '老', '老师', '师', '师生', '生', '生前', '前', '前来', '来', '就', '就餐', '餐']

     

    在实际研究中,我们需要的并不是“完全切分”中得到文本中所有出现在词典中的单词所构成的链表,而是一个个确切的词组组成的句子。例如,我们希望“北京大学”是一个完整的词,而非“北京+大学”两个碎片。

    为此,我们需要完善一下我们的规则,考虑到越长的单词表达的意义越丰富,于是我们定义单词越长优先级越高。

    具体来说,就是在某个下标为起点递增查词的过程中,优先输出更长的单词,这种规则被称为最长匹配算法。该下标的扫描顺序如果是从前往后,则称正向最长匹配,反之则称逆向最长匹配。

    正向最长匹配

    import load_dictionary # 载入加载词典的函数
    
    def forward_segment(text, dic):
        word_list = []
        i = 0
        while i < len(text):  # i 当前扫描位置在text中的位置下标
            longest_word = text[i]  # 当前扫描位置的单字
            for j in range(i + 1, len(text) + 1):  # j 遍历当前扫描位置中所有可能的结尾
                word = text[i:j]  # 从当前位置到结尾的连续字符串
                if word in dic:  # 如果存在于词典中
                    if len(word) > len(longest_word):  # 词语越长优先级越高
                        longest_word = word
            word_list.append(longest_word)  # 输出最长词
            i += len(longest_word)  # 正向扫描:将词语长度加到扫描位置的位置下标中
        return word_list
    
    if __name__ == '__main__':
        dic = load_dictionary()
        print(forward_segment('项目的研究', dic))
        print(forward_segment('商品和服务', dic))
        print(forward_segment('研究生命起源', dic))
        print(forward_segment('当下雨天地面积水', dic))
        print(forward_segment('结婚的和尚未结婚的', dic))
        print(forward_segment('欢迎新老师生前来就餐', dic))

    运行结果

    ['项目', '的', '研究']
    ['商品', '和服', '务']
    ['研究生', '命', '起源']
    ['当下', '雨天', '地面', '积水']
    ['结婚', '的', '和尚', '未', '结婚', '的']
    ['欢迎', '新', '老师', '生前', '来', '就餐']

    逆向最长匹配

    因为正向最长匹配很容易遇到诸如“研究生命起源”中因“研究生”优先级大于“研究”的误差,因此,有人提出了逆向匹配的方法。

    import load_dictionary  # 载入加载词典的函数
    
    def backward_segment(text, dic):
        word_list = []
        i = len(text) - 1  # 从text中的最后一个字开始扫描
        while i >= 0:  # i 当前扫描位置在text中的位置下标
            longest_word = text[i]  # 扫描位置的单字
            for j in range(0, i):  # 遍历[0, i]区间中所有可能的起点
                word = text[j: i + 1]  # 取出[j, i]区间作为待查询单词
                if word in dic:  # 如果存在于词典中
                    if len(word) > len(longest_word):  # 词语越长优先级越高
                        longest_word = word
                        break
            word_list.insert(0, longest_word)  # 逆向扫描,所以越先查出的单词在位置上越靠后
            i -= len(longest_word)  # 正向扫描:将词语长度减到扫描位置的位置下标中
        return word_list
    
    if __name__ == '__main__':
        dic = load_dictionary()
        print(backward_segment('项目的研究', dic))
        print(backward_segment('商品和服务', dic))
        print(backward_segment('研究生命起源', dic))
        print(backward_segment('当下雨天地面积水', dic))
        print(backward_segment('结婚的和尚未结婚的', dic))
        print(backward_segment('欢迎新老师生前来就餐', dic))

    运行结果

    ['项', '目的', '研究']
    ['商品', '和', '服务']
    ['研究', '生命', '起源']
    ['当', '下雨天', '地面', '积水']
    ['结婚', '的', '和', '尚未', '结婚', '的']
    ['欢', '迎新', '老', '师生', '前来', '就餐']

    双向最长匹配

    逆向最长匹配虽然拆分“研究生命起源”得到了正确结果,但是在拆分“项目的研究”时却出现了新的问题。因此,有的人又提出了综合两种规则,期待它们取长补短的方法,称之为双向匹配。

    双向匹配的逻辑流程如下:

    1. 同时执行正向和逆向最长匹配
    2. 若两者的词数不同,则返回次数更少的哪一个
    3. 若两者的词数相同,则返回两者中单字更少的哪一个
    4. 若两者的单字数也相同,则优先返回逆向最长匹配的结果

    这种规则的出发点来自语言学中的启发——汉字中单字词的数量要远远小于非单字词。因此,算法应当尽量减少结果中的单字,保留更多的完整词语,这样的算法也称启发式算法

    from book.N001_HanLP_Load_dictionary import load_dictionary  # 载入加载词典的函数
    from book.N003_HanLP_Forward_Segment import forward_segment  # 载入正向最长匹配的函数
    from book.N004_HanLP_Backward_segment import backward_segment  # 载入逆向最长匹配的函数
    
    def count_single_char(word_list: list):  # 统计单字成词的个数
        return sum(1 for word in word_list if len(word) == 1)
    
    def bidirectional_segment(text, dic):
        f = forward_segment(text, dic)
        b = backward_segment(text, dic)
        if len(f) < len(b):  # 词数更少优先级更高
            return f
        elif len(f) > len(b):
            return b
        else:
            if count_single_char(f) < count_single_char(b):  # 单字更少优先级更高
                return f
            else:
                return b  # 都相等时逆向匹配优先级更高
    
    if __name__ == '__main__':
        dic = load_dictionary()
        print(bidirectional_segment('项目的研究', dic))
        print(bidirectional_segment('商品和服务', dic))
        print(bidirectional_segment('研究生命起源', dic))
        print(bidirectional_segment('当下雨天地面积水', dic))
        print(bidirectional_segment('结婚的和尚未结婚的', dic))
        print(bidirectional_segment('欢迎新老师生前来就餐', dic))

    运行结果

    ['项', '目的', '研究']
    ['商品', '和', '服务']
    ['研究', '生命', '起源']
    ['当下', '雨天', '地面', '积水']
    ['结婚', '的', '和', '尚未', '结婚', '的']
    ['欢', '迎新', '老', '师生', '前来', '就餐']

    总体来说,这三种匹配方法都不能正确地解决所有的例子,由此可以看到基于词典规则的系统的脆弱。

    根据《自然语言处理入门》中的评测,这三种匹配方式的运行速度大致如下:

    • 正向匹配和逆向匹配的速度差不多,是双向匹配速度的两倍
    • Python的运行速度比Java慢,效率只有Java的一半不到

    学习使用教材:《自然语言处理入门》(何晗):2.1 - 2.3

    本文中代码大部分引自该书中的代码,个人还是很推荐这本书的,确实是非常好的教材。

    展开全文
  • 三种写法都是先按照一定的规则进行字符串的切分,然后将其统计起来。 代码 package org.feng.java8; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java....

    文章目录

    思想

    三种写法都是先按照一定的规则进行字符串的切分,然后将其统计起来。

    代码

    package org.feng.java8;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    
    /**
     *
     *  统计单词个数练习
     * @author Feng
     * @date 2020/10/6 13:44
     */
    public class WordCountDemo {
        /**正则匹配:(1-n个)空格、英文逗号、英文句号*/
        private static Pattern pattern = Pattern.compile("[,.]| +");
    
        /**
         * 方法1
         * @param line
         * @param map
         * @return
         */
        public static Map<String, Integer> method1(String line, Map<String, Integer> map){
            String[] words = pattern.split(line);
            for (String word : words) {
                map.merge(word, 1, (theOriginal, present) -> theOriginal + 1);
            }
            return map;
        }
    
    
        /**
         * 方法2
         * @param line
         * @return
         */
        public static Map<String, Long> method2(String line){
            return pattern.splitAsStream(line)
                    .collect(Collectors.groupingBy(word -> word, Collectors.counting()));
        }
    
    
        /**
         * 方法3
         * @param line
         * @return
         */
        public static Map<String, Integer> method3(String line){
            String[] words = pattern.split(line);
            Map<String, Integer> result = new HashMap<>(16);
            for (String word : words) {
                result.put(word, result.getOrDefault(word, 0) + 1);
            }
            return result;
        }
    
        /**
         * 测试运行
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            Map<String, Integer> map = new HashMap<>(16);
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line;
            StringBuilder sb = new StringBuilder();
            while((line = br.readLine()) != null && !"bye".equals(line)){
                sb.append(line);
            }
    
            // 输出结果
            // System.out.println(method1(sb.toString(), map));
            //System.out.println(method2(sb.toString()));
            //System.out.println(method3(sb.toString()));
        }
    }
    
    
    
    
    展开全文
  • ElasticSearch各种分词器

    2020-01-05 14:13:57
    1. ES分词器 分词器是专门处理分词的组件,Analyzer由三部分组成:...Tokenizer:按照分词器规则进行切分单词, Token Filters:将切分后的单词进行加工,小写,删除空格,增加同义词等。 2. ES内置的分词器 2...

    1. ES分词器

    分词器是专门处理分词的组件,Analyzer由三部分组成:Character Filters、Tokenizer、Token Filters。

    • Character Filters:对文本原始处理,如去除html,
    • Tokenizer:按照分词器规则进行切分单词,
    • Token Filters:将切分后的单词进行加工,小写,删除空格,增加同义词等。

    2. ES内置的分词器

    2.1 Standard Analyzer默认分词器

    按词进行切分,小写处理,停用词不做处理(the、a、is)

    2.2 Simple Analyzer

    简单分词器,按照非字母切分,不是字母将被过滤,符号被过滤,小写处理。

    2.3 Stop Analyzer

    小写处理,停用词过滤(the、a、is)

    2.4 Whitespace Analyzer

    按照空格切分,不做大小写处理

    2.5 Keyword Analyzer

    不分词,直接将输入当作输出

    2.6 Patter Analyzer

    正则表达式,默认\W+ (非字符分割)

    2.7 其他分词器

    当ElasticSearch自带的分词器无法满足时,还可以自定义分词器,可以自定义分词器,通过自组合不同的组件实现

    • Character Filter
    • Tokenizer
    • Token Filter
      在Tokenizer之前对文本进行处理,例如增加删除及替换字符。可以配置多个Character Filters。会影响Tokenizer的position和offset信息。
      一些自带的Character Filters
    • html strip 去除html标签
    • mapping 字符串替换
    • pattern replace 正则匹配替换
    # 使用char filter 将-替换为_
    PUT _analyze
    {
      "tokenizer":"standard",
      "char_filter":[
        {
          "type": "mapping",
          "mappings": ["- => _"]
        }  
      ]
    }
    

    3. 使用analyzer api

    GET /_analyze
    {
      "analyzer": "standard",
      "text":"ElasticSearch learning"
    }
    
    POST books/_analyzer
    {
    	"field":"title",
    	"text":"ElasticSearch in action"
    }
    
    
    展开全文
  • elasticsearch 分词介绍

    2020-05-18 14:28:53
    Tokenizer:按照规则切分单词 Token Filters:对切分结果进行处理,小写、删除、stopwords、增加同义词 elasticsearch 内置了很多分词器,这些分词器的组合各不相同。 // 直接指定Analyzer 进行测试 GET /_...
  • Analysis就是分词的过程,将文档内容转换为一系列单词(term),...Tokenizer 按具体规则将文档切分单词;Token Filter 将切分单词进行加工处理,小写,删除stopwords等。 ES内置分词器 analyzer desc Stand
  • 在中文分词技术中的匹配切分输入规则分词方式,这是一种机械分词的方式,我们通过机器词典中的单词与语句中的每个词语进行匹配,如果匹配成功则切分,如果匹配失败则不与切分。 在匹配切分中,原则是“长.
  • 语言分析包org.apache.lucene.analysis

    千次阅读 2010-11-26 15:18:00
    对英文而言,其分词规则很简单,因为每个单词间都有一个空格,按空格取单词即可,当然为了提高英文检索的准确度,也可以把一些短语作为一个整体,其间不切分,这就需要一个词库,对德文、俄文也是类似,稍有不同。...
  • Elasticsearch Analysis

    2020-01-26 14:07:31
    Analyzer 的组成 分词器是专门处理分词的组件,Analyzer 由三部分组成 ...Token Filter - 将切分单词进行加工,小写,删除 stopwords,增加同义词 Elasticsearch 内置分析器 分析器 作用 Standard ...
  • Analyzer

    2020-03-24 22:19:11
    analysis--文本分析是把全文本转化成一系列单词(term/tocken)的过程,也叫分词 analyzer --分词器是专门处理分词的组件,它有...Tocken Filter 将切分单词进行加工,小写,删除stopwords(停用词)和增加同义词 es内置...
  • NLP - 分词

    2021-05-01 17:11:03
    英文单词天然以空格分隔,汉语对词的构成边界很难进行界定。 中文分词方法可归纳为 规则分词 统计分词 混合分词(规则+统计) 规则分词 人工设立词库,按照一定方式进行匹配切分 优点:简单高效 缺点:无法处理未...
  • 自定义分词器 当 ElasticSearch 自带的分词器无法满足需要时,可以自定义分词器,通过组合不同的组件实现;...Token Filters:将切分单词进行加工,小写,删除 stopwords,增加同义词; Character Filt...
  • 自然语言处理学习笔记(1)——词典分词 一、相关定义(P32) 中文分词:将一段文本拆分为一系列单词的过程,...完全切分指的是:找出一段文本中的所有单词(并不是标准意义上的分词),不考虑效率的话,朴素的完全
  • 分词算法

    2019-10-14 14:12:14
    基于规则的分词是一种机械分词方法,主要是通过维护词典,在切分语句时,将语句的每个字符串与词表中的词进行逐一匹配,找到则切分,否则不予切分。按照匹配切分的方式,主要有正向最大匹配法、逆向最大匹配法以及...
  • IK分词器实战

    2021-02-19 19:50:36
    Token Filter:将切分单词进行加工,小写,删除stopwords,增加同义词 以上三部分是串行处理的关系,除Tokenizer只能一个外,其他两个都可以多个。IK分词器仅实现了Tokenizer IK分词器原理 IK分词器在是一款基于...
  • Elasticsearch简单总结

    2019-05-29 15:52:08
    ES内置默认的standard 分词器对中文很不友好,是单字切分的,所以我们使用了ik分词器,ik分词器有最小切分和最细度切分两种 分词器对内容进行预处理,比如过滤掉HTML标签等特殊符号,再进行分词,标准化(比如统一一...
  • 中文分词

    2019-10-31 18:45:26
    中文分词:将一段文本拆分为一系列单词的过程。其算法大致可分为基于词典规则和基于机器学习两个类别。 ...词典确定后,制定一些切分算法,常用的规则有:正向最长匹配、逆向最长匹配、双向最长...
  • 2) 依次读入源程序符号,对源程序进行单词切分和识别,直到源程序结束; 3) 对正确的单词,按照它的种别以<种别码,值>的形式保存在符号表中; 4) 对不正确的单词,做出错误处理。 算符优先算法: 若输入文法: E->...
  • 词典分词

    2020-05-10 22:08:43
    正向最长匹配 ,即在完全切分基础上加了一个规则:优先选取长度更长的单词 逆向最长匹配,即将正向匹配的扫描顺序改为从后到前 正向和逆向都有各自出现歧义的情况,融合两种匹配 双向最长匹配,即同时运行两者,若词...
  • 中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,需要人为切分。根据其特点,可以把分词算法分为四大类: ·基于规则的分词方法 ·...
  • 词典分词2.1 什么是词2.2 词典2.3 切分算法2.4 字典树2.5 基于字典树的其它算法2.6 HanLP的词典分词实现2.7 GitHub项目 2. 词典分词 中文分词:指的是将一段文本拆分为一系列单词的过程,这些单词顺序拼接后等于原...
  • 如果没有数据的时候,那只能通过正则或者规则来解决问题 但是有些基于概率的方法,必须有一定的数据 首先我们要对句子进行切分,使用分词 接着进行预处理:拼写纠错、stemming(将不同的单词转换到原型)、停用词过滤...
  • Lucene-分词器(三)

    2017-01-03 22:37:00
    分词器能以某种规则对关键字进行分词,将分好的词放到目录中,以作为检索到的条件,在创建索引时会使用到分词器,在搜索时也将用到分词器。 2.分词器的一般工作流程 2.1切分关键词 2.2去除停用词 2.3对于英文单词,...
  • Lucene Analyzer(分词器)

    2012-04-19 22:53:23
    分词器能以某种规则对关键字进行分词,将分好的词放到目录中,以作为检索到的条件,在创建索引时会使用到分词器,在搜索时也将用到分词器,这两个地方要使用同一个分词器,否则可能找不到结果.分词器一般的工作流程: ...
  • 上课我们介绍了倒排索引,在里面提到了分词的概念,分词器就是用来分词的。 分词器是ES中专门处理分词的组件,英文为Analyzer,定义为:...Tokenizer:将原始文本按照一定规则切分为单词 Token Filters:针对...
  • python/正则表达式

    2020-07-14 22:46:51
    文章目录正则表达式进阶re模块切分字符串分组: 正则表达式 字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的...
  • lucene的分词器宝典

    2018-12-10 15:50:00
    Analyzer类(分词器)就是把一段文本中的词按某些规则取出,提供和以后查询时使用的工具类,注意在创建索引时会用到分词器,在使用字符串搜索时也会用到分词器,这两个地方要使用同一个分词器,否则可能会搜索不出...
  • 中文分词:MMSEG

    2018-03-13 19:14:28
    概述单词是一个基本的语义单元,不同于英文,中文句子中没有词的界限,因此进行中文自然语言处理,通常需要先进行分词,分词效果将直接影响词性、句法树等模块的效果。中文分词算法大概分为两大类:一是基于字符串...

空空如也

空空如也

1 2
收藏数 35
精华内容 14
关键字:

切分单词规则