精华内容
下载资源
问答
  • 中文分词工具

    2018-05-27 00:52:51
    本文给出了10大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 10大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...

    本文的目标有两个:

    1、学会使用10大Java开源中文分词器

    2、对比分析10 大Java开源中文分词器的分词效果

    本文给出了10大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。

    10大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义一个统一的接口:

    /**
     * 获取文本的所有分词结果, 对比不同分词器结果
     * @author 
     */
    public interface WordSegmenter {
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,去除重复
         */
        default public Set<String> seg(String text) {
            return segMore(text).values().stream().collect(Collectors.toSet());
        }
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,KEY 为分词器模式,VALUE 为分词器结果
         */
        public Map<String, String> segMore(String text);
    }

    从上面的定义我们知道,在Java中,同样的方法名称和参数,但是返回值不同,这种情况不可以使用重载。

    这两个方法的区别在于返回值,每一个分词器都可能有多种分词模式,每种模式的分词结果都可能不相同,第一个方法忽略分词器模式,返回所有模式的所有不重复分词结果,第二个方法返回每一种分词器模式及其对应的分词结果。

    在这里,需要注意的是我们使用了Java8中的新特性默认方法,并使用stream把一个map的value转换为不重复的集合。

    下面我们利用这10大分词器来实现这个接口:

    1、word分词器

    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      for(SegmentationAlgorithm segmentationAlgorithm : SegmentationAlgorithm.values()){
        map.put(segmentationAlgorithm.getDes(), seg(text, segmentationAlgorithm));
      }
      return map;
    }
    private static String seg(String text, SegmentationAlgorithm segmentationAlgorithm) {
      StringBuilder result = new StringBuilder();
      for(Word word : WordSegmenter.segWithStopWords(text, segmentationAlgorithm)){
        result.append(word.getText()).append(" ");
      }
      return result.toString();
    }

    2、Ansj分词器

    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      StringBuilder result = new StringBuilder();
      for(Term term : BaseAnalysis.parse(text)){
        result.append(term.getName()).append(" ");
      }
      map.put("BaseAnalysis", result.toString());
      result.setLength(0);
      for(Term term : ToAnalysis.parse(text)){
        result.append(term.getName()).append(" ");
      }
      map.put("ToAnalysis", result.toString());
      result.setLength(0);
      for(Term term : NlpAnalysis.parse(text)){
        result.append(term.getName()).append(" ");
      }
      map.put("NlpAnalysis", result.toString());
      result.setLength(0);
      for(Term term : IndexAnalysis.parse(text)){
        result.append(term.getName()).append(" ");
      }
      map.put("IndexAnalysis", result.toString());
      return map;
    }

    3、Stanford分词器

    private static final StanfordCoreNLP CTB = new StanfordCoreNLP("StanfordCoreNLP-chinese-ctb");
    private static final StanfordCoreNLP PKU = new StanfordCoreNLP("StanfordCoreNLP-chinese-pku");
    private static final PrintStream NULL_PRINT_STREAM = new PrintStream(new NullOutputStream(), false);
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("Stanford Beijing University segmentation", seg(PKU, text));
      map.put("Stanford Chinese Treebank segmentation", seg(CTB, text));
      return map;
    }
    private static String seg(StanfordCoreNLP stanfordCoreNLP, String text){
      PrintStream err = System.err;
      System.setErr(NULL_PRINT_STREAM);
      Annotation document = new Annotation(text);
      stanfordCoreNLP.annotate(document);
      List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
      StringBuilder result = new StringBuilder();
      for(CoreMap sentence: sentences) {
        for (CoreLabel token: sentence.get(CoreAnnotations.TokensAnnotation.class)) {
          String word = token.get(CoreAnnotations.TextAnnotation.class);;
          result.append(word).append(" ");
        }
      }
      System.setErr(err);
      return result.toString();
    }

    4、FudanNLP分词器

    private static CWSTagger tagger = null;
    static{
      try{
        tagger = new CWSTagger("lib/fudannlp_seg.m");
        tagger.setEnFilter(true);
      }catch(Exception e){
        e.printStackTrace();
      }
    }
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("FudanNLP", tagger.tag(text));
      return map;
    }

    5、Jieba分词器

    private static final JiebaSegmenter JIEBA_SEGMENTER = new JiebaSegmenter();
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("INDEX", seg(text, SegMode.INDEX));
      map.put("SEARCH", seg(text, SegMode.SEARCH));
      return map;
    }
    private static String seg(String text, SegMode segMode) {
      StringBuilder result = new StringBuilder();				
      for(SegToken token : JIEBA_SEGMENTER.process(text, segMode)){
        result.append(token.word.getToken()).append(" ");
      }
      return result.toString(); 
    }

    6、Jcseg分词器

    private static final JcsegTaskConfig CONFIG = new JcsegTaskConfig();
    private static final ADictionary DIC = DictionaryFactory.createDefaultDictionary(CONFIG);
    static {
      CONFIG.setLoadCJKSyn(false);
      CONFIG.setLoadCJKPinyin(false);
    }
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("复杂模式", segText(text, JcsegTaskConfig.COMPLEX_MODE));
      map.put("简易模式", segText(text, JcsegTaskConfig.SIMPLE_MODE));
      return map;
    }
    private String segText(String text, int segMode) {
      StringBuilder result = new StringBuilder();		
      try {
        ISegment seg = SegmentFactory.createJcseg(segMode, new Object[]{new StringReader(text), CONFIG, DIC});
        IWord word = null;
        while((word=seg.next())!=null) {		 
          result.append(word.getValue()).append(" ");
        }
      } catch (Exception ex) {
        throw new RuntimeException(ex);
      }
      return result.toString();
    }

    7、MMSeg4j分词器

    private static final Dictionary DIC = Dictionary.getInstance();
    private static final SimpleSeg SIMPLE_SEG = new SimpleSeg(DIC);
    private static final ComplexSeg COMPLEX_SEG = new ComplexSeg(DIC);
    private static final MaxWordSeg MAX_WORD_SEG = new MaxWordSeg(DIC);
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put(SIMPLE_SEG.getClass().getSimpleName(), segText(text, SIMPLE_SEG));
      map.put(COMPLEX_SEG.getClass().getSimpleName(), segText(text, COMPLEX_SEG));
      map.put(MAX_WORD_SEG.getClass().getSimpleName(), segText(text, MAX_WORD_SEG));
      return map;
    }
    private String segText(String text, Seg seg) {
      StringBuilder result = new StringBuilder();
      MMSeg mmSeg = new MMSeg(new StringReader(text), seg);		
      try {
        Word word = null;
        while((word=mmSeg.next())!=null) {	   
          result.append(word.getString()).append(" ");
        }
      } catch (IOException ex) {
        throw new RuntimeException(ex);
      }
      return result.toString();
    }

    8、IKAnalyzer分词器

    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("智能切分", segText(text, true));
      map.put("细粒度切分", segText(text, false));
      return map;
    }
    private String segText(String text, boolean useSmart) {
      StringBuilder result = new StringBuilder();
      IKSegmenter ik = new IKSegmenter(new StringReader(text), useSmart);		
      try {
        Lexeme word = null;
        while((word=ik.next())!=null) {		  
          result.append(word.getLexemeText()).append(" ");
        }
      } catch (IOException ex) {
        throw new RuntimeException(ex);
      }
      return result.toString();
    }

    9、Paoding分词器

    private static final PaodingAnalyzer ANALYZER = new PaodingAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("MOST_WORDS_MODE", seg(text, PaodingAnalyzer.MOST_WORDS_MODE));
      map.put("MAX_WORD_LENGTH_MODE", seg(text, PaodingAnalyzer.MAX_WORD_LENGTH_MODE));
      return map;
    }
    private static String seg(String text, int mode){
      ANALYZER.setMode(mode);
      StringBuilder result = new StringBuilder();
      try {
        Token reusableToken = new Token();
        TokenStream stream = ANALYZER.tokenStream("", new StringReader(text));
        Token token = null;
        while((token = stream.next(reusableToken)) != null){
          result.append(token.term()).append(" ");
        }
      } catch (Exception ex) {
        throw new RuntimeException(ex);
      }
      return result.toString();		  
    }

    10、smartcn分词器

    private static final SmartChineseAnalyzer SMART_CHINESE_ANALYZER = new SmartChineseAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
      Map<String, String> map = new HashMap<>();
      map.put("smartcn", segText(text));
      return map;
    }
    private static String segText(String text) {
      StringBuilder result = new StringBuilder();
      try {
        TokenStream tokenStream = SMART_CHINESE_ANALYZER.tokenStream("text", new StringReader(text));
        tokenStream.reset();
        while (tokenStream.incrementToken()){
          CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
          result.append(charTermAttribute.toString()).append(" ");
        }
        tokenStream.close();
      }catch (Exception e){
        e.printStackTrace();
      }
      return result.toString();
    }

    现在我们已经实现了本文的第一个目的:学会使用10大Java开源中文分词器。

    最后我们来实现本文的第二个目的:对比分析 10大Java开源中文分词器的分词效果,程序如下:

    public static Map<String, Set<String>> contrast(String text){
      Map<String, Set<String>> map = new LinkedHashMap<>();
      map.put("word分词器", new WordEvaluation().seg(text));
      map.put("Stanford分词器", new StanfordEvaluation().seg(text));
      map.put("Ansj分词器", new AnsjEvaluation().seg(text));
      map.put("FudanNLP分词器", new FudanNLPEvaluation().seg(text));
      map.put("Jieba分词器", new JiebaEvaluation().seg(text));
      map.put("Jcseg分词器", new JcsegEvaluation().seg(text));
      map.put("MMSeg4j分词器", new MMSeg4jEvaluation().seg(text));
      map.put("IKAnalyzer分词器", new IKAnalyzerEvaluation().seg(text));
      map.put("Paoding分词器", new PaodingEvaluation().seg(text));
      map.put("smartcn分词器", new SmartCNEvaluation().seg(text));
      return map;
    }
    public static Map<String, Map<String, String>> contrastMore(String text){
      Map<String, Map<String, String>> map = new LinkedHashMap<>();
      map.put("word分词器", new WordEvaluation().segMore(text));
      map.put("Stanford分词器", new StanfordEvaluation().segMore(text));
      map.put("Ansj分词器", new AnsjEvaluation().segMore(text));
      map.put("FudanNLP分词器", new FudanNLPEvaluation().segMore(text));
      map.put("Jieba分词器", new JiebaEvaluation().segMore(text));
      map.put("Jcseg分词器", new JcsegEvaluation().segMore(text));
      map.put("MMSeg4j分词器", new MMSeg4jEvaluation().segMore(text));
      map.put("IKAnalyzer分词器", new IKAnalyzerEvaluation().segMore(text));
      map.put("Paoding分词器", new PaodingEvaluation().segMore(text));
      map.put("smartcn分词器", new SmartCNEvaluation().segMore(text));
      return map;
    }
    public static void show(Map<String, Set<String>> map){
      map.keySet().forEach(k -> {
        System.out.println(k + " 的分词结果:");
        AtomicInteger i = new AtomicInteger();
        map.get(k).forEach(v -> {
          System.out.println("\t" + i.incrementAndGet() + " 、" + v);
        });
      });
    }
    public static void showMore(Map<String, Map<String, String>> map){
      map.keySet().forEach(k->{
        System.out.println(k + " 的分词结果:");
        AtomicInteger i = new AtomicInteger();
        map.get(k).keySet().forEach(a -> {
          System.out.println("\t" + i.incrementAndGet()+ " 、【"   + a + "】\t" + map.get(k).get(a));
        });
      });
    }
    public static void main(String[] args) {
      show(contrast("杨尚川是APDPlat应用级产品开发平台的作者"));
      showMore(contrastMore("杨尚川是APDPlat应用级产品开发平台的作者"));
    }

    运行结果如下:

    word分词器 的分词结果:
      1 、杨尚川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
      2 、杨尚川 是 apdplat 应用级 产品 开发平台 的 作者 
      3 、杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      4 、杨尚川 是 apdplat 应用级 产品 开发 平台 的 作者 
    Stanford分词器 的分词结果:
      1 、杨 尚 川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
      2 、杨 尚川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
    Ansj分词器 的分词结果:
      1 、杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、杨 杨尚川 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      3 、杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      4 、杨尚川 是 apdplat 应用级 产品 开发 平台 的 作者 
    FudanNLP分词器 的分词结果:
      1 、杨尚川 是 APDPlat应 用级 产品 开发 平台 的 作者
    Jieba分词器 的分词结果:
      1 、杨尚川 是 apdplat 应用 级 产品 开发 产品开发 平台 的 作者 
      2 、杨尚川 是 apdplat 应用 级 产品开发 平台 的 作者 
    Jcseg分词器 的分词结果:
      1 、杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、杨 尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    MMSeg4j分词器 的分词结果:
      1 、杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    IKAnalyzer分词器 的分词结果:
      1 、杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    Paoding分词器 的分词结果:
      1 、杨尚 尚川 apdplat 应用 级 产品 开发 平台 作者
    smartcn分词器 的分词结果:
      1 、杨 尚 川 是 apdplat 应用 级 产品 开发 平 台 的 作者
    word分词器 的分词结果:
      1 、【全切分算法】	杨尚川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
      2 、【双向最大最小匹配算法】	杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      3 、【正向最大匹配算法】	杨尚川 是 apdplat 应用级 产品 开发平台 的 作者 
      4 、【双向最大匹配算法】	杨尚川 是 apdplat 应用级 产品 开发平台 的 作者 
      5 、【逆向最大匹配算法】	杨尚川 是 apdplat 应用级 产品 开发平台 的 作者 
      6 、【正向最小匹配算法】	杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      7 、【双向最小匹配算法】	杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      8 、【逆向最小匹配算法】	杨尚川 是 apdplat 应用级 产品 开发 平台 的 作者 
    Stanford分词器 的分词结果:
      1 、【Stanford Chinese Treebank segmentation】	杨 尚 川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
      2 、【Stanford Beijing University segmentation】	杨 尚川 是 APDPlat 应用 级 产品 开发 平台 的 作者 
    Ansj分词器 的分词结果:
      1 、【BaseAnalysis】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、【IndexAnalysis】	杨 杨尚川 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      3 、【ToAnalysis】	杨尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      4 、【NlpAnalysis】	杨尚川 是 apdplat 应用级 产品 开发 平台 的 作者 
    FudanNLP分词器 的分词结果:
      1 、【FudanNLP】	杨尚川 是 APDPlat应 用级 产品 开发 平台 的 作者
    Jieba分词器 的分词结果:
      1 、【SEARCH】	杨尚川 是 apdplat 应用 级 产品开发 平台 的 作者 
      2 、【INDEX】	杨尚川 是 apdplat 应用 级 产品 开发 产品开发 平台 的 作者 
    Jcseg分词器 的分词结果:
      1 、【简易模式】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、【复杂模式】	杨 尚川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    MMSeg4j分词器 的分词结果:
      1 、【SimpleSeg】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、【ComplexSeg】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      3 、【MaxWordSeg】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    IKAnalyzer分词器 的分词结果:
      1 、【智能切分】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
      2 、【细粒度切分】	杨 尚 川 是 apdplat 应用 级 产品 开发 平台 的 作者 
    Paoding分词器 的分词结果:
      1 、【MAX_WORD_LENGTH_MODE】	杨尚 尚川 apdplat 应用 级 产品 开发 平台 作者 
      2 、【MOST_WORDS_MODE】	杨尚 尚川 apdplat 应用 级 产品 开发 平台 作者
    smartcn分词器 的分词结果:
      1 、【smartcn】	杨 尚 川 是 apdplat 应用 级 产品 开发 平 台 的 作者
    
    展开全文
  • 中文分词中间件的设计与实现,张静,宋俊德,中文分词技术是中文信息处理的基础,具有广泛的应用场景。开发者在确定采用何种中文分词系统之前,通常需要比较不同中文分词系统
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...

    本文的目标有两个:

    1、学会使用11大Java开源中文分词器

    2、对比分析11大Java开源中文分词器的分词效果

    本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。

    11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义一个统一的接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
     * 获取文本的所有分词结果, 对比不同分词器结果
     * @author 杨尚川
     */
    public interface WordSegmenter {
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,去除重复
         */
        default public Set<String> seg(String text) {
            return segMore(text).values().stream().collect(Collectors.toSet());
        }
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,KEY 为分词器模式,VALUE 为分词器结果
         */
        public Map<String, String> segMore(String text);
    }

    从上面的定义我们知道,在Java中,同样的方法名称和参数,但是返回值不同,这种情况不可以使用重载。

    这两个方法的区别在于返回值,每一个分词器都可能有多种分词模式,每种模式的分词结果都可能不相同,第一个方法忽略分词器模式,返回所有模式的所有不重复分词结果,第二个方法返回每一种分词器模式及其对应的分词结果。

    在这里,需要注意的是我们使用了Java8中的新特性默认方法,并使用stream把一个map的value转换为不重复的集合。

     

    下面我们利用这11大分词器来实现这个接口:

    1、word分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        for(SegmentationAlgorithm segmentationAlgorithm : SegmentationAlgorithm.values()){
            map.put(segmentationAlgorithm.getDes(), seg(text, segmentationAlgorithm));
        }
        return map;
    }
    private static String seg(String text, SegmentationAlgorithm segmentationAlgorithm) {
        StringBuilder result = new StringBuilder();
        for(Word word : WordSegmenter.segWithStopWords(text, segmentationAlgorithm)){
            result.append(word.getText()).append(" ");
        }
        return result.toString();
    }

    2、Ansj分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
     
        StringBuilder result = new StringBuilder();
        for(Term term : BaseAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("BaseAnalysis", result.toString());
     
        result.setLength(0);
        for(Term term : ToAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("ToAnalysis", result.toString());
     
        result.setLength(0);
        for(Term term : NlpAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("NlpAnalysis", result.toString());
     
        result.setLength(0);
        for(Term term : IndexAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("IndexAnalysis", result.toString());
     
        return map;
    }

    3、Stanford分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    private static final StanfordCoreNLP CTB = new StanfordCoreNLP("StanfordCoreNLP-chinese-ctb");
    private static final StanfordCoreNLP PKU = new StanfordCoreNLP("StanfordCoreNLP-chinese-pku");
    private static final PrintStream NULL_PRINT_STREAM = new PrintStream(new NullOutputStream(), false);
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("Stanford Beijing University segmentation", seg(PKU, text));
        map.put("Stanford Chinese Treebank segmentation", seg(CTB, text));
        return map;
    }
    private static String seg(StanfordCoreNLP stanfordCoreNLP, String text){
        PrintStream err = System.err;
        System.setErr(NULL_PRINT_STREAM);
        Annotation document = new Annotation(text);
        stanfordCoreNLP.annotate(document);
        List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
        StringBuilder result = new StringBuilder();
        for(CoreMap sentence: sentences) {
            for (CoreLabel token: sentence.get(CoreAnnotations.TokensAnnotation.class)) {
                String word = token.get(CoreAnnotations.TextAnnotation.class);;
                result.append(word).append(" ");
            }
        }
        System.setErr(err);
        return result.toString();
    }

    4、FudanNLP分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    private static CWSTagger tagger = null;
    static{
        try{
            tagger = new CWSTagger("lib/fudannlp_seg.m");
            tagger.setEnFilter(true);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("FudanNLP", tagger.tag(text));
        return map;
    }

    5、Jieba分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    private static final JiebaSegmenter JIEBA_SEGMENTER = new JiebaSegmenter();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("INDEX", seg(text, SegMode.INDEX));
        map.put("SEARCH", seg(text, SegMode.SEARCH));
        return map;
    }
    private static String seg(String text, SegMode segMode) {
        StringBuilder result = new StringBuilder();                
        for(SegToken token : JIEBA_SEGMENTER.process(text, segMode)){
            result.append(token.word.getToken()).append(" ");
        }
        return result.toString(); 
    }

    6、Jcseg分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    private static final JcsegTaskConfig CONFIG = new JcsegTaskConfig();
    private static final ADictionary DIC = DictionaryFactory.createDefaultDictionary(CONFIG);
    static {
        CONFIG.setLoadCJKSyn(false);
        CONFIG.setLoadCJKPinyin(false);
    }
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
     
        map.put("复杂模式", segText(text, JcsegTaskConfig.COMPLEX_MODE));
        map.put("简易模式", segText(text, JcsegTaskConfig.SIMPLE_MODE));
     
        return map;
    }
    private String segText(String text, int segMode) {
        StringBuilder result = new StringBuilder();        
        try {
            ISegment seg = SegmentFactory.createJcseg(segMode, new Object[]{new StringReader(text), CONFIG, DIC});
            IWord word = null;
            while((word=seg.next())!=null) {         
                result.append(word.getValue()).append(" ");
            }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    7、MMSeg4j分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    private static final Dictionary DIC = Dictionary.getInstance();
    private static final SimpleSeg SIMPLE_SEG = new SimpleSeg(DIC);
    private static final ComplexSeg COMPLEX_SEG = new ComplexSeg(DIC);
    private static final MaxWordSeg MAX_WORD_SEG = new MaxWordSeg(DIC);
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put(SIMPLE_SEG.getClass().getSimpleName(), segText(text, SIMPLE_SEG));
        map.put(COMPLEX_SEG.getClass().getSimpleName(), segText(text, COMPLEX_SEG));
        map.put(MAX_WORD_SEG.getClass().getSimpleName(), segText(text, MAX_WORD_SEG));
        return map;
    }
    private String segText(String text, Seg seg) {
        StringBuilder result = new StringBuilder();
        MMSeg mmSeg = new MMSeg(new StringReader(text), seg);        
        try {
            Word word = null;
            while((word=mmSeg.next())!=null) {       
                result.append(word.getString()).append(" ");
            }
        catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    8、IKAnalyzer分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
     
        map.put("智能切分", segText(text, true));
        map.put("细粒度切分", segText(text, false));
     
        return map;
    }
    private String segText(String text, boolean useSmart) {
        StringBuilder result = new StringBuilder();
        IKSegmenter ik = new IKSegmenter(new StringReader(text), useSmart);        
        try {
            Lexeme word = null;
            while((word=ik.next())!=null) {          
                result.append(word.getLexemeText()).append(" ");
            }
        catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    9、Paoding分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    private static final PaodingAnalyzer ANALYZER = new PaodingAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
     
        map.put("MOST_WORDS_MODE", seg(text, PaodingAnalyzer.MOST_WORDS_MODE));
        map.put("MAX_WORD_LENGTH_MODE", seg(text, PaodingAnalyzer.MAX_WORD_LENGTH_MODE));
         
        return map;
    }
    private static String seg(String text, int mode){
        ANALYZER.setMode(mode);
        StringBuilder result = new StringBuilder();
        try {
            Token reusableToken = new Token();
            TokenStream stream = ANALYZER.tokenStream(""new StringReader(text));
            Token token = null;
            while((token = stream.next(reusableToken)) != null){
                result.append(token.term()).append(" ");
            }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();          
    }

    10、smartcn分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    private static final SmartChineseAnalyzer SMART_CHINESE_ANALYZER = new SmartChineseAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("smartcn", segText(text));
        return map;
    }
    private static String segText(String text) {
        StringBuilder result = new StringBuilder();
        try {
            TokenStream tokenStream = SMART_CHINESE_ANALYZER.tokenStream("text"new StringReader(text));
            tokenStream.reset();
            while (tokenStream.incrementToken()){
                CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
                result.append(charTermAttribute.toString()).append(" ");
            }
            tokenStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return result.toString();
    }

    11、HanLP分词器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    private static final Segment N_SHORT_SEGMENT = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
    private static final Segment DIJKSTRA_SEGMENT = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("标准分词", standard(text));
        map.put("NLP分词", nlp(text));
        map.put("索引分词", index(text));
        map.put("N-最短路径分词", nShort(text));
        map.put("最短路径分词", shortest(text));
        map.put("极速词典分词", speed(text));
        return map;
    }
    private static String standard(String text) {
        StringBuilder result = new StringBuilder();
        StandardTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String nlp(String text) {
        StringBuilder result = new StringBuilder();
        NLPTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String index(String text) {
        StringBuilder result = new StringBuilder();
        IndexTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String speed(String text) {
        StringBuilder result = new StringBuilder();
        SpeedTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String nShort(String text) {
        StringBuilder result = new StringBuilder();
        N_SHORT_SEGMENT.seg(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String shortest(String text) {
        StringBuilder result = new StringBuilder();
        DIJKSTRA_SEGMENT.seg(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }

    现在我们已经实现了本文的第一个目的:学会使用11大Java开源中文分词器。

    最后我们来实现本文的第二个目的:对比分析11大Java开源中文分词器的分词效果,程序如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    public static Map<String, Set<String>> contrast(String text){
        Map<String, Set<String>> map = new LinkedHashMap<>();
        map.put("word分词器"new WordEvaluation().seg(text));
        map.put("Stanford分词器"new StanfordEvaluation().seg(text));
        map.put("Ansj分词器"new AnsjEvaluation().seg(text));
        map.put("HanLP分词器"new HanLPEvaluation().seg(text));
        map.put("FudanNLP分词器"new FudanNLPEvaluation().seg(text));
        map.put("Jieba分词器"new JiebaEvaluation().seg(text));
        map.put("Jcseg分词器"new JcsegEvaluation().seg(text));
        map.put("MMSeg4j分词器"new MMSeg4jEvaluation().seg(text));
        map.put("IKAnalyzer分词器"new IKAnalyzerEvaluation().seg(text));
        map.put("smartcn分词器"new SmartCNEvaluation().seg(text));
        return map;
    }
    public static Map<String, Map<String, String>> contrastMore(String text){
        Map<String, Map<String, String>> map = new LinkedHashMap<>();
        map.put("word分词器"new WordEvaluation().segMore(text));
        map.put("Stanford分词器"new StanfordEvaluation().segMore(text));
        map.put("Ansj分词器"new AnsjEvaluation().segMore(text));
        map.put("HanLP分词器"new HanLPEvaluation().segMore(text));
        map.put("FudanNLP分词器"new FudanNLPEvaluation().segMore(text));
        map.put("Jieba分词器"new JiebaEvaluation().segMore(text));
        map.put("Jcseg分词器"new JcsegEvaluation().segMore(text));
        map.put("MMSeg4j分词器"new MMSeg4jEvaluation().segMore(text));
        map.put("IKAnalyzer分词器"new IKAnalyzerEvaluation().segMore(text));
        map.put("smartcn分词器"new SmartCNEvaluation().segMore(text));
        return map;
    }
    public static void show(Map<String, Set<String>> map){
        map.keySet().forEach(k -> {
            System.out.println(k + " 的分词结果:");
            AtomicInteger i = new AtomicInteger();
            map.get(k).forEach(v -> {
                System.out.println("\t" + i.incrementAndGet() + " 、" + v);
            });
        });
    }
    public static void showMore(Map<String, Map<String, String>> map){
        map.keySet().forEach(k->{
            System.out.println(k + " 的分词结果:");
            AtomicInteger i = new AtomicInteger();
            map.get(k).keySet().forEach(a -> {
                System.out.println("\t" + i.incrementAndGet()+ " 、【"   + a + "】\t" + map.get(k).get(a));
            });
        });
    }
    public static void main(String[] args) {
        show(contrast("我爱楚离陌"));
        showMore(contrastMore("我爱楚离陌"));
    }

    运行结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ********************************************
    word分词器 的分词结果:
        1 、我 爱 楚离陌 
    Stanford分词器 的分词结果:
        1 、我 爱 楚 离陌 
        2 、我 爱 楚离陌 
    Ansj分词器 的分词结果:
        1 、我 爱 楚离 陌 
        2 、我 爱 楚 离 陌 
    HanLP分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    smartcn分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    FudanNLP分词器 的分词结果:
        1 、我 爱楚离陌
    Jieba分词器 的分词结果:
        1 、我爱楚 离 陌 
    Jcseg分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    MMSeg4j分词器 的分词结果:
        1 、我爱 楚 离 陌 
    IKAnalyzer分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    ********************************************
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    ********************************************
    word分词器 的分词结果:
        1 、【全切分算法】 我 爱 楚离陌 
        2 、【双向最大最小匹配算法】    我 爱 楚离陌 
        3 、【正向最大匹配算法】  我 爱 楚离陌 
        4 、【双向最大匹配算法】  我 爱 楚离陌 
        5 、【逆向最大匹配算法】  我 爱 楚离陌 
        6 、【正向最小匹配算法】  我 爱 楚离陌 
        7 、【双向最小匹配算法】  我 爱 楚离陌 
        8 、【逆向最小匹配算法】  我 爱 楚离陌 
    Stanford分词器 的分词结果:
        1 、【Stanford Chinese Treebank segmentation】 我 爱 楚离陌 
        2 、【Stanford Beijing University segmentation】   我 爱 楚 离陌 
    Ansj分词器 的分词结果:
        1 、【BaseAnalysis】  我 爱 楚 离 陌 
        2 、【IndexAnalysis】 我 爱 楚 离 陌 
        3 、【ToAnalysis】    我 爱 楚 离 陌 
        4 、【NlpAnalysis】   我 爱 楚离 陌 
    HanLP分词器 的分词结果:
        1 、【NLP分词】 我 爱 楚 离 陌 
        2 、【标准分词】  我 爱 楚 离 陌 
        3 、【N-最短路径分词】  我 爱 楚 离 陌 
        4 、【索引分词】  我 爱 楚 离 陌 
        5 、【最短路径分词】    我 爱 楚 离 陌 
        6 、【极速词典分词】    我 爱 楚 离 陌 
    smartcn分词器 的分词结果:
        1 、【smartcn】   我 爱 楚 离 陌 
    FudanNLP分词器 的分词结果:
        1 、【FudanNLP】  我 爱楚离陌
    Jieba分词器 的分词结果:
        1 、【SEARCH】    我爱楚 离 陌 
        2 、【INDEX】 我爱楚 离 陌 
    Jcseg分词器 的分词结果:
        1 、【简易模式】  我 爱 楚 离 陌 
        2 、【复杂模式】  我 爱 楚 离 陌 
    MMSeg4j分词器 的分词结果:
        1 、【SimpleSeg】 我爱 楚 离 陌 
        2 、【ComplexSeg】    我爱 楚 离 陌 
        3 、【MaxWordSeg】    我爱 楚 离 陌 
    IKAnalyzer分词器 的分词结果:
        1 、【智能切分】  我 爱 楚 离 陌 
        2 、【细粒度切分】 我 爱 楚 离 陌 
    ********************************************

     

     

     

     


    做中文搜索,关键词提取,文档分类都离不开中文分词,能用的代码包有如下

      • 单字切分 sphinx只要把min_word_len设置为1,并配置charset_table,默认就是单字切分,lucene用StandardAnalyzer

      • CJKAnalyzer lucene自带,两两分词,就是把 ABCD 分成 AB,BC,CD 3段

      • PaodingAnalyzer 开源,可以用于lucene http://code.google.com/p/paoding/

      • sphinx-for-chinese 基于词频字典,sphinx中文分词专属插件,http://www.sphinx-search.com

      • MMseg 基于词典+最大匹配+歧义消除,sphinx和lucence都能用,(sphinx可以直接使用coreseek.com的版本)MMseg还有 python,ruby,php,java等各种语言的开发包

      • smallseg 很轻量级的python库,只能单独使用不能集成到(lucene或者sphinx)当中

      • jieba 另一个python分词库 https://github.com/fxsjy/jieba

      • ICTCLAS 中科院的分词算法,sphinx和lucene都能用,但是使用比较麻烦,还分商业版和免费版

     

     

     

     

     

    中文分词与搜索引擎

     

     

    看到题目就知道我要说什么了,这个话题好像已经被讨论过n次了,看雅虎搜索blog上在06年就有过专题系列文章,地址为:http://ysearchblog.cn/2006/07/post_16.html,文中详细的介绍了有关中文分词的意义,算法,跟搜索引擎的关系等等。个人认为文章质量非常不错。其实我所写的也不外乎这些东西,可我为什么还要写呢?是因为我花了将近一周的时间来理解中文分词,收集有关资料,为了不让努力白费,我还是总结一下吧。

    一.为什么要中文分词?

    对啊,为何要分词,不分词行不行?要讨论这个话题,首先需要了解一下搜索引擎的原理。搜索引擎的为什么能快速检索到自己查询的关键字呢?实际上这得 益于他的数据存储机制-----倒排索引。这里用一个例子来大体说明什么是倒排索引(之所以说大体,是因为我也没有深入的了解)。假设我有10篇文章,他 们可能论述了相同或不同的主题。如果我想看看哪篇文中含有“中文分词”这个词语,我可以这么干:循环遍历每一篇文章,看看他的内容中有没有含有“中文分 词”这个词语,然后把含有目标词语的文章返回。很显然,我需要打开10篇文章,并且从头到尾的遍历每篇文章,看能不能匹配到“中文分词”,这样的效率是很 低的,对于毫秒级的搜索引擎来说是绝对不能接受的。所以我要给每篇文章做个“目录”!不是你想查询“中文分词”吗?好,我事先找到含有“中文分词”的文 章。假设文章1,3,5,7含有这个词语,文章2,4,6,7含有“搜索引擎”,好,我建立一个对应关系表“中文分词——>1,3,5,7”,“搜 索引擎——>2,4,6,7”,于是当你要检索“中文分词”这个词语的时候,我不再打开每篇文章去匹配,而是直接到对应关系表去看一下“中文分词” 对应着文章1,3,5,7,好,结果出来了,文章1,3,5,7含有“中文分词”这个词语,同样检索“搜索引擎”,返回的结果是2,4,6,7。那我要同 时检索“中文分词”和“搜索引擎”呢?那就是(1,3,5,7)跟(2,4,6,7)取交集!结果是文章7同 时含有“中文分词”,“搜索引擎”。那我搜其他的词语呢?那就把其他词语也放到这个对应表中。这个“对应关系表”其实就是所谓的倒排索引,当然,倒排索引 可能含有的信息更为丰富,比如不仅包含了词语在哪一篇文章,同时还包含了在这篇文章的哪个位置等等。很显然,我们需要把所有文章建立一个倒排索引。问题来 了,计算机怎么认识哪个是词语呢?他并不知道“中文分词”就是一个词语。没有词语,怎么建立索引呢?于是,我们需要中文分词!并且分词发生在用户查询和服 务器建立索引时。

    二.什么样的中文分词适合搜索引擎

    因为中文的每个句子是连续的字的序列,词语跟词语直接没有明显的分隔(英文的单词之间用格隔开),于是分词看起来变得困难了许多。取一个最极端的方式,每一个字作为一个词,即所谓的1元分词。比如“山东经济学院”,分为“山_东_经_济_学_院”,然后建立倒排索引:

    山——>1,3

    东——>2,3

    经——>3,4

    济——>3,5,4

    院——>3,5,6

    于是,当我搜索“山东经济学院”时,在倒排索引中查找每一个字,然后取其交集,得到的结果是3,文章3中 含有“山东经济学院”这个词。这看起来很完美,完全解决了分词的问题并成功的建立了倒排索引。显然,博大精深的汉语不可能让问题就这么简单!如果我按照一 元分词对“主板和服务器”,建立倒排索引,当我想要检索日本的“和服”时。出来的结果却是“主板和服务器”八竿子打不着的结果。不免让人云里雾里心头不 爽!除了检索质量,还有一个问题就是检索效率,对“山东经济学院”我需要查询到6条目录,然后取交集。这性能又降低了,对于毫秒级的搜索引擎,这怎么能忍 呢。如果“山东经济学院”就是一个词,建立索引“山东经济学院——>3”我岂不是一下子就查到了,也不用做什么交集运算。所以1元分词显然不能满足 人们的要求。类似的还有2元分词,2元交叉分词,比如“主板和服务器”,2元分词为:“主板_和服_务器”,2元交叉分词为“主板_板和_和服_服务_务 器,很显然,这两种分词结果除了提高了一下检索效率外,对搜索体验却没什么大的改善,总会让我在查找“和服”时找到一堆关于电脑的东西。

           那 上面提到的“山东经济学院”作为一个词的策略是否完美呢?这里就体现出搜索引擎的中文分词跟其他专业领域的中文分词的不同来,如果是机器翻译,很显然“山 东经济学院”是一个专有名词,不可分割。但是对于搜索引擎,我希望当我查询“经济学院”时也能查到山东经济学院,这样的话“山东经济学院”又不能作为一个 词了。

           所以,搜索引擎的分词应该控制合理的粒度!

           问题是,怎样才算合适的粒度?我认为是能表达完整意义的最小词语,有些拗口,解释一下:“山东经济学院”,可以分为“山东_经济学院”或“山东_经济_学 院”,我倾向的是后者,因为“经济学院”是可以再分的:“经济_学院”。“经济”和“学院”都是可以理解的能表达完整意义的词语,并且不可再分。这样便保 证了查全率:“经济学院”,“山东_学院”都能检索到这条结果。至于搜索的满意程度就需要做相关度排序,跟搜索词语越相关的排在前面,比如搜索“山东经 济”,一篇关于阐述山东经济发展的文章应该在比较靠前的位置,而关于山东经济学院的文章则应排在后面。

    三.中文分词算法

    中文分词有三种截然不同的分词方法,每一种方法都对应了一种研究领域。

    1.  基于词典的分词

    2.  基于统计的分词

    3.  基于语法的分词

    我所了解的,及当前搜索引擎广为采用的是第一种分词方法,有一个包含了很多词语的词典,你拿着一句话挨着到词典里去匹配,匹配上就算一个词。比如 “山东经济学院”,首先匹配“山”,词典里有,OK, 算一个词,“山东”,词典里也有,那也是一个词,假设“山东经济”也包含在词典里呢?那我同时匹配到“山”,“山东”,“山东经济”三个词语,我该选择哪 个呢?为了解决这个问题,人们便制定了一些规则:选择长度最大的那个词语,因为实践证明这往往是正确的(当然,不是绝对正确)。根据这个规则演变的算法有 正向最大匹配,逆向最大匹配,MMSEG算法等。上述各种算法都不是完美的,总会有分错的时候,我们只是期望尽可能的正确(其实,对于搜索引擎,有时候分 词不正确也并不影响检索效果)。

           下面以“研究生命起源”这句话为例讲述一下上述三种算法的分词情况:

    首先,我们需要一个词典,词典里含有这么几个词:

    研究

    研究生

    生命

    起源

    1.  正向最大匹配

    顾名思义,方向为从前往后正向匹配。

     

    首先,拿到第一个词“研”,查询词典,没有,前进一步,拿到“研究”,查询词典,得到词语:“研 究”,并不罢休,继续拿到“研究生”,查询词典,得到词语:“研究生”,仍不罢休,拿到“研究生命”,查询词典,没有,继续下去,一直打到你认为合理的长 度,比如你觉得一个词语不可能超过5个字,你拿到“研究生命起”,查询词典后,没有结果,就不在继续下去了。现在对查询结果进行选择,很显然长度最大的为 “研究生”,至此,我们确定了第一个词“研究生”。

     

    然后,从下一个词开始,依次拿到“命”,“命起”,“命起源”,到词典查询,都没有结果,于是把“命”这个字作为一个词。

     

    再次,从下一个词开始,依次拿到“起”,“起源”,到词典查询,得到“起源”。

     

    至此分词完成,得到结果“研究生_命_起源”,很明显分错了~。

    2.  逆向最大匹配

    基本上还是上面的过程,不过“研究生命起源”这句话要到这来

    首先,依次拿到“源”,“起源”,“命起源”,“生命起源”,“究生命起源”到词典匹配,得到结果“起源”。

    然后,依次拿到“命”,“生命”,“究生命”,“研究生命”,到词典查询,得到结果“生命”。

    再次,依次拿到“究”,“研究”,查询词典,得到结果“研究”

     

    至此,分词完成,得到结果“研究_生命_起源”,分词正确。

     

    总体说来,普遍认为逆向最大匹配的正确率要高于正向最大匹配。

    3.  MMSEG算法

    MMSEG算法相对上面两种算法来说比较复杂,因为其正确率比较高所以被普遍采用,因为有各种语言的实现,比如python的pymmseg ,java 的mmseg4j, c/c++的libmmseg等,

    网上关于这个算法有很多介绍,为了偷懒,我在这里就不赘述,想了解的同学请google之。

    四.中文分词面临的问题

    当前中文分词主要面临两个问题:

    1.  歧义消解

    2.  新词发现

    关于歧义消解:

    比如“研究生命”,是应该分为“研究_生命”还是“研究生_命”,这是关于“生”的归属问题,“生”可以跟“研究”一起,变成“研究生”,也可以跟 “命”一起,变成“生命”。“研究生”跟“生命”有一个交集“命”,这便是交叉型歧义。另一个例子“中国人”,可以分为“中国_人”,也可以“中国人”整 个是一个词。即“中国”和“人”的不同组合造成了歧义,这便是组合型歧义

    上述各种算法无非就是对这两种歧义的消解。

    按照我在第二条提到的观点,搜索引擎分词的粒度应该是:能表达完整意义的最小词语。所以应该不会出现组合型歧义,重点应该放到解决“交叉型歧义”的问题上。

    歧义的消解应该针对特殊情况做出合理的调整。可以结合不同的分词方法,比如语法分析,统计等。

    举例来说:“武夷山路”,词典中含有“武夷”,“山路”两个词的时候,MMSEG算法和逆向最大匹配会分词为:“武夷_山 路”,当用户输入“武夷山路”时,不管分词正确与否,都能正确匹配到正确的结果。但是,在这个城市里生活的人们,可能想通过“武夷山”就能检索到武夷山路 (因为大家都知道这个城市里没有武夷山,输入“武夷山”,默认想得到的结果就是关于武夷山路的)。现在来看分词为什么错误了呢?因为词典里存在“山路”这 个词!是“路”这个仅仅起后缀作用的字干扰了分词,所以我认为这样的后缀词,不应该参与分词,类似的还有“省,市,县,镇”等。

    关于新词发现:

    因为精力有限,目前还不了解这个领域的情况,大体可以通过对用户搜索日志进行数据挖掘得出。

    五.总结

    1.  搜索引擎需要中文分词,分词的对象为要建立索引的文档和用户提交的查询词,并且两者对同一段语句的分词结果必须一致。

    2.  分词粒度应该控制为:能表达完整意义的最小词语。这样便避免了组合型歧义。

    3.  对于消解歧义应该根据具体情况调整,适当综合利用各种分词方法。

    4.  如果用户查询词跟建立索引时分词结果一致,就算分词错误,也能检索到,所以有人认为当分词正确率达到一定值时,正确率对搜索质量的影响便不会那么明显了。因此没必要一味的追求正确率。

    六.参考资料

    1.  中文分词和搜索引擎(一)

    2.  中文分词和搜索引擎(二)

    3.  中文分词和搜索引擎(三)

    4.  搜索引擎之中文分词(Chinese Word Segmentation)简介

    5.  Google

     

     

     

     

    当前几个主要的Lucene中文分词器的比较

    1. 基本介绍:

    paoding :Lucene中文分词“庖丁解牛” Paoding Analysis
    imdict :imdict智能词典所采用的智能中文分词程序
    mmseg4j : 用 Chih-Hao Tsai 的 MMSeg 算法 实现的中文分词器
    ik :采用了特有的“正向迭代最细粒度切分算法“,多子处理器分析模式

    2. 开发者及开发活跃度:

    paoding :qieqie.wang, google code 上最后一次代码提交:2008-06-12,svn 版本号 132
    imdict :XiaoPingGao, 进入了 lucene contribute,lucene trunk 中 contrib/analyzers/smartcn/ 最后一次提交:2009-07-24,
    mmseg4j :chenlb2008,google code 中 2009-08-03 (昨天),版本号 57,log为:mmseg4j-1.7 创建分支
    ik :linliangyi2005,google code 中 2009-07-31,版本号 41

    3. 用户自定义词库:

    paoding :支持不限制个数的用户自定义词库,纯文本格式,一行一词,使用后台线程检测词库的更新,自动编译更新过的词库到二进制版本,并加载
    imdict :暂时不支持用户自定义词库。但 原版 ICTCLAS 支持。支持用户自定义 stop words
    mmseg4j :自带sogou词库,支持名为 wordsxxx.dic, utf8文本格式的用户自定义词库,一行一词。不支持自动检测。 -Dmmseg.dic.path
    ik : 支持api级的用户词库加载,和配置级的词库文件指定,无 BOM 的 UTF-8 编码, 分割。不支持自动检测。

    4. 速度(基于官方介绍,非自己测试)

    paoding :在PIII 1G内存个人机器上,1秒 可准确分词 100万 汉字
    imdict :483.64 (字节/秒),259517(汉字/秒)
    mmseg4j : complex 1200kb/s左右, simple 1900kb/s左右
    ik :具有50万字/秒的高速处理能力

    5. 算法和代码复杂度

    paoding :svn src 目录一共1.3M,6个properties文件,48个java文件,6895 行。使用不用的 Knife 切不同类型的流,不算很复杂。
    imdict :词库 6.7M(这个词库是必须的),src 目录 152k,20个java文件,2399行。使用ICTCLAS HHMM隐马尔科夫模型,“利用大量语料库的训练来统计汉语词汇的词频和跳转概率,从而根据这些统计结果对整个汉语句子计算最似然(likelihood)的切分”
    mmseg4j : svn src 目录一共 132k,23个java文件,2089行。MMSeg 算法 ,有点复杂。
    ik : svn src 目录一共6.6M(词典文件也在里面),22个java文件,4217行。多子处理器分析,跟paoding类似,歧义分析算法还没有弄明白。

    6. 文档

    paoding :几乎无。代码里有一些注释,但因为实现比较复杂,读代码还是有一些难度的。
    imdict : 几乎无。 ICTCLAS 也没有详细的文档,HHMM隐马尔科夫模型的数学性太强,不太好理解。
    mmseg4j : MMSeg 算法 是英文的,但原理比较简单。实现也比较清晰。
    ik : 有一个pdf使用手册,里面有使用示例和配置说明。

    7. 其它

    paoding :引入隐喻,设计比较合理。search 1.0 版本就用的这个。主要优势在于原生支持词库更新检测。主要劣势为作者已经不更新甚至不维护了。
    imdict :进入了 lucene trunk,原版 ictclas 在各种评测中都有不错的表现,有坚实的理论基础,不是个人山寨。缺点为暂时不支持用户词库。
    mmseg4j : 在complex基础上实现了最多分词(max-word),但是还不成熟,还有很多需要改进的地方。
    ik :  针对Lucene全文检索优化的查询分析器IKQueryParser

    8. 结论

    个人觉得,可以在 mmseg4j 和 paoding 中选一个。关于这两个分词效果的对比,可以参考:

    http://blog.chenlb.com/2009/04/mmseg4j-max-word-segment-compare-with-paoding-in-effect.html

    或者自己再包装一下,将 paoding 的词库更新检测做一个单独的模块实现,然后就可以在所有基于词库的分词算法之间无缝切换了。

    ps,对不同的 field 使用不同的分词器是一个可以考虑的方法。比如 tag 字段,就应该使用一个最简单的分词器,按空格分词就可以了。

    本文来自:http://blog.fulin.org/2009/08/lucene_chinese_analyzer_compare.html

     

     

     

     

     

    深入浅出Hadoop Mahout数据挖掘实战(算法分析、项目实战、中文分词技术) 

    Mahout简介

    Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,

    提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序

    Mahout相关资源

    Mahout主页:http://mahout.apache.org/

    Mahout 最新版本0.8下载: http://mirrors.hust.edu.cn/apache/mahout/0.8/ 

    使用mahout-distribution-0.8.tar.gz可试跑,源码在mahout-distribution-0.8-src.tar.gz中

    Mahout 简要安装步骤:

    如无需修改源代码,只是试用试跑,请无需安装maven(网上许多教程会有这个弯路,请跳过),具体可以参考以下教程

    http://www.hadoopor.com/thread-983-1-1.html

    如果需要能修改源代码并重新编译打包,需要安装maven,请参考如下图文教程:http://wenku.baidu.com/view/dbd15bd276a20029bd642d55.html

    Mahout 专业教程 : Mahout in action http://yunpan.taobao.com/share/link/R56BdLH5O

    注: 出版时间2012年, 对应mahout版本0.5, 是目前mahout最新的书籍读物。目前只有英文版,但是翻了一下,里面词汇基本都是计算机基础词汇,且配图和源代码,是适合阅读的。

    IBM mahout简介: http://www.ibm.com/developerworks/cn/java/j-mahout/

    注:中文版, 更新是时间为09年,但是里面对于mahout阐述较全面,推荐阅读,特别是最后的书籍清单,适合深入了解

     

     

    课程介绍

    本课程主要涉及以下内容的讲解:

    1、Mahout数据挖掘工具 

    2、Hadoop实现推荐系统的综合实战,涉及到MapReduce、Pig和Mahout的综合实战

    课程针对人群

    1、本课程适合于有一定java基础知识,对数据库和sql语句有一定了解,熟练使用linux系统的技术人员,特别适合于想换工作或寻求高薪职业的人士

    2、最好有Greenplum Hadoop、Hadoop2.0、YARN、Sqoop、FlumeAvro、 Mahout等大数据基础,学习过北风课程《Greenplum 分布式数据库开发入门到精通》、《全面深入Greenplum Hadoop大数据分析平台》、《Hadoop2.0、YARN深入浅出》、《MapReduce、Hbase进阶提升》、《MapReduce、Hbase进阶提升》为最佳。

     

     

     

    课程大纲

    Mahout数据挖掘工具(10课时)

    数据挖掘概念、系统组成

    数据挖掘常用方法及算法(回归分析、分类、聚类等)

    数据挖掘分析工具

    Mahout支持的算法

    Mahout起源和特点

    Mahout安装、配置及测试

    实战:Mahout K-means聚类分析

    Mahout实现Canopy算法

    Mahout实现分类算法

    实战:Mahout逻辑回归分类预测

    实战:Mahout朴素贝叶斯分类

    推荐系统的概念及分类

    协同过滤推荐算法概念、分类及应用

    实战:实现基于Mahout的电影推荐系统

    Hadoop综合实战-文本挖掘项目(7课时)

    文本挖掘的概念及应用场景

    项目背景

    项目流程

    中文分词技术

    庖丁分词器的使用

    MapReduce并行分词程序的设计与实现

    Pig划分数据集

    Mahout构建朴素贝叶斯文本分类器

    模型应用-计算用户偏好类别

     

     

     

     

     

    分词技术

     
     

     

    目录(?)[+]

    我们要理解分词技术先要理解一个概念。那就是查询处理,当用户向搜索引擎提交查询后,搜索引擎接收到用户的信息要做一系列的处理。步骤如下所示:

    1.首先是到数据库里面索引相关的信息,这就是查询处理。

    那么查询处理又是如何工作的呢?很简单,把用户提交的字符串没有超过3个的中文字,就会直接到数据库索引词汇。超过4个中文字的,首先用分隔符比如空格,标点符号,将查询串分割成若干子查询串。

    举个例子。“什么是百度分词技术” 我们就会把这个词分割成“ 什么是,百度,分词技术。”这种分词方法叫做反向匹配法。

    2.然后再看用户提供的这个词有没有重复词汇

    如果有的话,会丢弃掉,默认为一个词汇。接下来检查用户提交的字符串,有没有字母和数字。如果有的话,就把字母和数字认为一个词。

    这就是搜索引擎的查询处理。

    分词的原理:

    百度是如何来分词的呢?分词技术现今非常成熟了。分为3种技术。

    字符串匹配的分词方法

    这是种常用的分词法,百度就是用此类分词。字符串匹配的分词方法,又分为3种分词方法。

    (1).正向最大匹配法

    就是把一个词从左至右来分词。

    举个例子:”不知道你在说什么”

    这句话采用正向最大匹配法是如何分的呢?“不知道,你,在,说什么”。

    (2).反向最大匹配法

    "不知道你在说什么"反向最大匹配法来分上面这段是如何分的。“不,知道,你在,说,什么”,这个就分的比较多了,反向最大匹配法就是从右至左。

    (3).就是最短路径分词法。

    就是说一段话里面要求切出的词数是最少的。

    “不知道你在说什么”最短路径分词法就是指,把上面那句话分成的词要是最少的。“不知道,你在,说什么”,这就是最短路径分词法,分出来就只有3个词了。

    (4).双向最大匹配法。

    而有一种特殊的情况,就是关键词前后组合内容被认为粘性相差不大,而搜索结果中也同时包含这两组词的话,百度会进行正反向同时进行分词匹配。

    词义分词法

    就是一种机器语音判断的分词方法。很简单,进行句法、语义分析,利用句法信息和语义信息来处理歧义现象来分词,这种分词方法,还不成熟,处在测试阶段。

    统计分词法

    根据词组的统计,就会发现两个相邻的字出现的频率最多,那么这个词就很重要。就可以作为用户提供字符串中的分隔符,这样来分词。

    比如,“我的,你的,许多的,这里,这一,那里”等等,这些词出现的比较多,就从这些词里面分开来。

     

     

    搜索引擎中文分词技术

      由于很多朋友要求写一篇搜索引擎分词技术的文章,特别是关于百度分词的。我今天就发发给大家

      Moon 10月9号在SEOWHY周四答疑群给讲解的分词技术今天给大家帖出来供大家学习一下。

      分词技术 : 什么是分词, 如何分词搜索引擎会承认,这次第一位朋友提的问题,想必大家也听说过,很好奇,什么是分词技术,什么又是百度分词呢?分词大家容易理解。就是一段词用字符分开,比如标点符号,空格等。

      那什么叫分词技术呢?分词技术就是SE针对用户提交查询的关键串进行的查询处理后根据用户的关键词串用各种匹配方法进行的一种技术。大家好好理 解。那么我们要理解分词技术先要理解一个概念。那就是查询处理,当用户向搜索引擎提交查询后,搜索隐藏接收到用户的信息要做一系列的处理。首先是到数据库 里面索引相关的信息,

      这就是查询处理,那么查询处理又是如何工作的呢?很简单,把用户提交的字符串没有超过3个的中文字,就会直接到数据库索引词汇。超过4个中文字 的,首先用分隔符比如空格,标点符号,将查询串分割成若干子查询串。举个例子。“什么是百度分词技术” 我们就会把这个词分割成“ 什么是,百度,分词技术。”这种分词方法叫做反向匹配法。2.然后再看用户提供的这个词有没有重复词汇。

      如果有的话,会丢弃掉,默认为一个词汇。接下来检查用户提交的字符串,有没有字母和数字。如果有的话,就把字母和数字认为一个词。好了,这就是SE的查询处理。

      讲了查询处理后,大家对分词技术,尤其是中文分词技术有了一个基本的了解。

      其实我讲的都是搜索引擎的原理。好了,我接下来讲分词的原理。我们用百度来举例

      百度是如何来分词的呢?分词技术现今非常成熟了。他分为3种技术。

      1.字符串匹配的分词方法

      2.词义分词法。

      3.统计分此法。

      先说第一种。

      也是常用的分词法,百度就是用此种分词。字符串匹配的分词方法,他又分为3中分词方法。

      1.正向最大匹配法

      什么意思呢?就是把一个词从左至右来分词。

      举个例子。

      “不知道你在说什么”

      这句话采用正向最大匹配法是如何分的呢?“不知道,你,在,说什么”与正向最大匹配法相对应的是反向最大匹配发。这是第二种分词方法。

      2.反向最大匹配法 来分上面我举的例子是如何分的呢 "不知道你在说什么"。反向最大匹配法来分上面这段是如何分的。“不,知道,你在,说,什么”,这个就分的比较多了,反向最大匹配法就是从右至左。

      3.就是最短路径分词法。

      这个什么理解呢 ,就是说 我一段话里面要求切出的词数是最少的。还是上面哪句话

      “不知道你在说什么”最短路径分词法就是指,我把上面哪句话分成的词要是最少的。不知道,你在,说什么,这就是最短路径分词法,分出来就只有3 个词了 。好了,当然还有上面三种可以相互结合组成一些分词方法。比如正向最大匹配法和反向最大匹配法组合起来就可以叫做双向最大匹配法。好了,第一种说完了,

      2.词义分词法。

      这种其实就是一种机器语音判断的分词

      方法。很简单,进行句法、语义分析,利用句法信息和语义信息来处理歧义现象来分词,这种分词方法,现在还不成熟。处在测试阶段。

      第三种,统计的分词方法。

      这个很简单,就是根据词组的统计,就会发现两个相邻的字出现的频率最多,那么这个词就很重要。就可以作为用户提供字符串中的分隔符。这样来分 词。比如,“我的,你的,许多的,这里,这一,那里”。等等,这些词出现的比较多,就从这些词里面分开来。好了,分词技术讲完了。

      那么我们刚刚学了分词技术,又如何来运用他们为我们的站点获得流量呢

      1.我们可以利用分词技术来增加我们站点长尾词。这样就可以获取流量排名。

      不但这些分出来的长尾词能够获取一定的排名,也能够推动站点的目标关键词获取很好的排名。这个原理就是内链原理,这里不再讲了。讲了这么多,我们举个例子。

      例如:三亚酒店预定,如何来分呢?

      正向最大匹配,反向最大匹配,双向最大匹配,最短链接匹配。

      1.正向最大匹配

      “三亚,酒店预定”

      2.反向最大匹配

      “三亚酒店,预定”

      3.双向最大匹配

      “三亚,酒店,预定”

      4.最短路径最大匹配。

      “三亚酒店预定”好了,我们分了词为

      “三亚,“酒店预定,预定,三亚酒店,三亚,酒店 ,三亚酒店预定。”

      这些词每个都可以做一个主题页为目标关键词

      这些分出来的词,把他们都作为你站点的主题页,导入链接权重上来了,竞争力就大了,因为这些页面把他内链起来。用锚链接,指向主页的目标关键 词。呵呵,这就是分词的好处。他能够提升目标关键词的排名的竞争力也同时给站点带来一定流量。一旦导入链接权重上来了,竞争力就大了,因为这些页面把他内 链起来。

      用锚链接,指向主页的目标关键词。呵呵,这就是分词的好处。他能够提升目标关键词的排名的竞争力也同时给站点带来一定流量。分词还有一种好处。 那就是提升内页的排名。好的,这个我就不详细讲了。因为我在SEOWHY已经写了一篇文章。大家可以去看一下。就是关于百度,捕获描述的文章。如果你的内 页不做描述,那么百度就会给你定义一个描述或者从你的页面捕获一个描述。在捕获描述的时候,如果你的知道他会捕获哪一段,那么你说,你的排名会不会上升。 你就刻意写哪一段。

      我写的那篇文章地址如下。大家可以去看一下。

      http://www.seowhy.com/bbs/thread-4451-1-1.html

     

    搜索引擎技术揭密:中文分词技术

      信息的飞速增长,使搜索引擎成为人们查找信息的首选工具,Google、百度、中国搜索等大型搜索引擎 一直是人们讨论的话题。随着搜索市场价值的不断增加,越来越多的公司开发出自己的搜索引擎,阿里巴巴的商机搜索、8848的购物搜索等也陆续面世,自然, 搜索引擎技术也成为技术人员关注的热点。

      搜索引擎技术的研究,国外比中国要早近十年,从最早的Archie,到后来的Excite,以 及altvista、overture、google等搜索引擎面世,搜索引擎发展至今,已经有十几年的历史,而国内开始研究搜索引擎是在上世纪末本世纪 初。在许多领域,都是国外的产品和技术一统天下,特别是当某种技术在国外研究多年而国内才开始的情况下。例如操作系统、字处理软件、浏览器等等,但搜索引 擎却是个例外。虽然在国外搜索引擎技术早就开始研究,但在国内还是陆续涌现出优秀的搜索引擎,像百度(http://www.baidu.com)等。目前在中文搜索引擎领域,国内的搜索引擎已经和国外的搜索引擎效果上相差不远。之所以能形成这样的局面,有一个重要的原因就在于中文和英文两种语言自身的书写方式不同,这其中对于计算机涉及的技术就是中文分词。

      什么是中文分词

       众所周知,英文是以词为单位的,词和词之间是靠空格隔开,而中文是以字为单位,句子中所有的字连起来才能描述一个意思。例如,英文句子I am a student,用中文则为:“我是一个学生”。计算机可以很简单通过空格知道student是一个单词,但是不能很容易明白“学”、“生”两个字合起来 才表示一个词。把中文的汉字序列切分成有意义的词,就是中文分词,有些人也称为切词。我是一个学生,分词的结果是:我 是 一个 学生。

      中文分词和搜索引擎

       中文分词到底对搜索引擎有多大影响?对于搜索引擎来说,最重要的并不是找到所有结果,因为在上百亿的网页中找到所有结果没有太多的意义,没有人能看得 完,最重要的是把最相关的结果排在最前面,这也称为相关度排序。中文分词的准确与否,常常直接影响到对搜索结果的相关度排序。笔者最近替朋友找一些关于日 本和服的资料,在搜索引擎上输入“和服”,得到的结果就发现了很多问题。下面就以这个例子来说明分词对搜索结果的影响,在现有三个中文搜索引擎上做测试, 测试方法是直接在Google(http://www.google.com)、百度(http://www.baidu.com)上以“和服”为关键词进行搜索:

      在Google上输入“和服”搜索所有中文简体网页,总共结果507,000条,前20条结果中有14条与和服一点关系都没有。

      在百度上输入“和服”搜索网页,总共结果为287,000条,前20条结果中有6条与和服一点关系都没有。

      在中搜上输入“和服”搜索网页,总共结果为26,917条,前20条结果都是与和服相关的网页。

      这次搜索引擎结果中的错误,就是由于分词的不准确所造成的。通过笔者的了解,Google的中文分词技术采用的是美国一家名叫Basis Technology(http://www.basistech.com)的公司提供的中文分词技术,百度使用的是自己公司开发的分词技术,中搜使用的是国内海量科技(http://www.hylanda.com)提供的分词技术。由此可见,中文分词的准确度,对搜索引擎结果相关性和准确性有相当大的关系。

      中文分词技术

      中文分词技术属于自然语言处理技术范畴,对于一句话,人可以通过自己的知识来明白哪些是词,哪些不是词,但如何让计算机也能理解?其处理过程就是分词算法。

      现有的分词算法可分为三大类:基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法。

      1、基于字符串匹配的分词方法

       这种方法又叫做机械分词方法,它是按照一定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行配,若在词典中找到某个字符串,则匹配成功 (识别出一个词)。按照扫描方向的不同,串匹配分词方法可以分为正向匹配和逆向匹配;按照不同长度优先匹配的情况,可以分为最大(最长)匹配和最小(最 短)匹配;按照是否与词性标注过程相结合,又可以分为单纯分词方法和分词与标注相结合的一体化方法。常用的几种机械分词方法如下:

      1)正向最大匹配法(由左到右的方向);

      2)逆向最大匹配法(由右到左的方向);

      3)最少切分(使每一句中切出的词数最小)。

       还可以将上述各种方法相互组合,例如,可以将正向最大匹配方法和逆向最大匹配方法结合起来构成双向匹配法。由于汉语单字成词的特点,正向最小匹配和逆向 最小匹配一般很少使用。一般说来,逆向匹配的切分精度略高于正向匹配,遇到的歧义现象也较少。统计结果表明,单纯使用正向最大匹配的错误率为1/169, 单纯使用逆向最大匹配的错误率为1/245。但这种精度还远远不能满足实际的需要。实际使用的分词系统,都是把机械分词作为一种初分手段,还需通过利用各 种其它的语言信息来进一步提高切分的准确率。

      一种方法是改进扫描方式,称为特征扫描或标志切分,优先在待分析字符串中识别和切分出一些 带有明显特征的词,以这些词作为断点,可将原字符串分为较小的串再来进机械分词,从而减少匹配的错误率。另一种方法是将分词和词类标注结合起来,利用丰富 的词类信息对分词决策提供帮助,并且在标注过程中又反过来对分词结果进行检验、调整,从而极大地提高切分的准确率。

      对于机械分词方法,可以建立一个一般的模型,在这方面有专业的学术论文,这里不做详细论述。

      2、基于理解的分词方法

       这种分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义 现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义 进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。由于汉语语言知识的笼统、复杂性,难以将各种语言信息组织成机器可 直接读取的形式,因此目前基于理解的分词系统还处在试验阶段。

      3、基于统计的分词方法

      从形式上看,词是稳定的字的组 合,因此在上下文中,相邻的字同时出现的次数越多,就越有可能构成一个词。因此字与字相邻共现的频率或概率能够较好的反映成词的可信度。可以对语料中相邻 共现的各个字的组合的频度进行统计,计算它们的互现信息。定义两个字的互现信息,计算两个汉字X、Y的相邻共现概率。互现信息体现了汉字之间结合关系的紧 密程度。当紧密程度高于某一个阈值时,便可认为此字组可能构成了一个词。这种方法只需对语料中的字组频度进行统计,不需要切分词典,因而又叫做无词典分词 法或统计取词方法。但这种方法也有一定的局限性,会经常抽出一些共现频度高、但并不是词的常用字组,例如“这一”、“之一”、“有的”、“我的”、“许多 的”等,并且对常用词的识别精度差,时空开销大。实际应用的统计分词系统都要使用一部基本的分词词典(常用词词典)进行串匹配分词,同时使用统计方法识别 一些新的词,即将串频统计和串匹配结合起来,既发挥匹配分词切分速度快、效率高的特点,又利用了无词典分词结合上下文识别生词、自动消除歧义的优点。

       到底哪种分词算法的准确度更高,目前并无定论。对于任何一个成熟的分词系统来说,不可能单独依靠某一种算法来实现,都需要综合不同的算法。笔者了解,海 量科技的分词算法就采用“复方分词法”,所谓复方,相当于用中药中的复方概念,即用不同的药才综合起来去医治疾病,同样,对于中文词的识别,需要多种算法 来处理不同的问题。

      分词中的难题

      有了成熟的分词算法,是否就能容易的解决中文分词的问题呢?事实远非如此。中文是一种十分复杂的语言,让计算机理解中文语言更是困难。在中文分词过程中,有两大难题一直没有完全突破。

      1、歧义识别

       歧义是指同样的一句话,可能有两种或者更多的切分方法。例如:表面的,因为“表面”和“面的”都是词,那么这个短语就可以分成“表面 的”和“表 面的”。这种称为交叉歧义。像这种交叉歧义十分常见,前面举的“和服”的例子,其实就是因为交叉歧义引起的错误。“化妆和服装”可以分成“化妆 和 服装”或者“化妆 和服 装”。由于没有人的知识去理解,计算机很难知道到底哪个方案正确。

      交叉歧义相对组合歧义来说是还算比较容易处 理,组合歧义就必需根据整个句子来判断了。例如,在句子“这个门把手坏了”中,“把手”是个词,但在句子“请把手拿开”中,“把手”就不是一个词;在句子 “将军任命了一名中将”中,“中将”是个词,但在句子“产量三年中将增长两倍”中,“中将”就不再是词。这些词计算机又如何去识别?

      如 果交叉歧义和组合歧义计算机都能解决的话,在歧义中还有一个难题,是真歧义。真歧义意思是给出一句话,由人去判断也不知道哪个应该是词,哪个应该不是词。 例如:“乒乓球拍卖完了”,可以切分成“乒乓 球拍 卖 完 了”、也可切分成“乒乓球 拍卖 完 了”,如果没有上下文其他的句子,恐怕谁也不知道“拍卖”在这里算不算一个词。

      2、新词识别

      新词,专业术语称为未登 录词。也就是那些在字典中都没有收录过,但又确实能称为词的那些词。最典型的是人名,人可以很容易理解句子“王军虎去广州了”中,“王军虎”是个词,因为 是一个人的名字,但要是让计算机去识别就困难了。如果把“王军虎”做为一个词收录到字典中去,全世界有那么多名字,而且每时每刻都有新增的人名,收录这些 人名本身就是一项巨大的工程。即使这项工作可以完成,还是会存在问题,例如:在句子“王军虎头虎脑的”中,“王军虎”还能不能算词?

      新词中除了人名以外,还有机构名、地名、产品名、商标名、简称、省略语等都是很难处理的问题,而且这些又正好是人们经常使用的词,因此对于搜索引擎来说,分词系统中的新词识别十分重要。目前新词识别准确率已经成为评价一个分词系统好坏的重要标志之一。

      中文分词的应用

       目前在自然语言处理技术中,中文处理技术比西文处理技术要落后很大一段距离,许多西文的处理方法中文不能直接采用,就是因为中文必需有分词这道工序。中 文分词是其他中文信息处理的基础,搜索引擎只是中文分词的一个应用。其他的比如机器翻译(MT)、语音合成、自动分类、自动摘要、自动校对等等,都需要用 到分词。因为中文需要分词,可能会影响一些研究,但同时也为一些企业带来机会,因为国外的计算机处理技术要想进入中国市场,首先也是要解决中文分词问题。 在中文研究方面,相比外国人来说,中国人有十分明显的优势。

      分词准确性对搜索引擎来说十分重要,但如果分词速度太慢,即使准确性再高, 对于搜索引擎来说也是不可用的,因为搜索引擎需要处理数以亿计的网页,如果分词耗用的时间过长,会严重影响搜索引擎内容更新的速度。因此对于搜索引擎来 说,分词的准确性和速度,二者都需要达到很高的要求。目前研究中文分词的大多是科研院校,清华、北大、中科院、北京语言学院、东北大学、IBM研究院、微 软中国研究院等都有自己的研究队伍,而真正专业研究中文分词的商业公司除了海量科技以外,几乎没有了。科研院校研究的技术,大部分不能很快产品化,而一个 专业公司的力量毕竟有限,看来中文分词技术要想更好的服务于更多的产品,还有很长一段路。

     

     

    浅述搜索引擎的两种分词算法

    21世纪互联网的快速发展让人们生活越来越便利,当日益剧增的海量信息让我们眼花缭乱时,搜索引擎的出现可以让我们快速找到自己想要的答案。因此多了解搜索引擎的分词算法,可以让网站在搜索引擎上获得更好的展现机会。在讲解中文分词技术之前,先来了解下全文检索技术

    全文检索技术

    全文检索是指索引程序扫描文章中的每个词并建立对应索引,记录该词出现的位置和次数。当通过搜索引擎查询时,检索程序就在记录的索引进行查找并返回 给用户。全文检索又分为基于字的全文索引和基于词的全文索引。基于字的全文索引会对内容中的每个字建立索引并记录,此方法查全率高,但查准率低,特别是对 于中文,有时搜索马克,会列出马克思的结果。基于词的全文索引是把一个词语作为一个单位进行索引记录,并能处理同义词。搜索引擎有自己的词库,当用户搜索 时,搜索引擎会从词库中抽取关键词作为索引项,这样可以大大提高检索的准确率。

    中文分词技术

    一 直以来大家都比较熟悉百度,百度有自己的中文分词技术。一般采用的包括正向最大匹配,反向最大匹配,最佳匹配法,专家系统方法等。其中最大正向匹配是最常 用的分词解决方案,它采用机械式算法,通过建立词典并进行正向最大匹配对中文进行分词。举个简单的例子比如搜索“北京大学在哪里”,则返回结果很多都是包 含北京大学,北大等词语的网页,搜索引擎就是采用正向最大匹配去判断,把北京大学当做一个词语来索引记录并返回。当然,正向最大匹配也有不完整性,比如长 度过长的词语,搜索引擎有时无法准确的分词,或者对前后都相互关联的词无法准确分词。例如“结合成分子时”,会被返回结合、成分、子时,而有时我们想要的 关键词是“分子”。

    很多时候百度都会根据自己词库中词语的权重进行拆分,权重的计算基于生活各个方面,比较复杂,搜索引擎要做的就是返回用户最想要的结果,有时站长们 做网站要站在用户的角度去考虑问题,其实这也是站在搜索引擎的角度考虑问题,不论在确定目标关键词或者是长尾关键词时,都可以根据中文分词的原理来选择, 这样可以最大化的减少无用功。

    分词原理不断在变化,不断在更新,我们应该继续学习,只有掌握了本质才能抓住实质。

    本文出自深圳网站建设,原文地址:http://www.68160.com ,欢迎大家和我交流,以后关于更多分词技术,特别是中文分词技术的更多应用我会陆续和大家分享。

     

     

     

    淘宝搜索:打造黄金标题之揭秘淘宝分词算法

    【淘宝搜索:打造黄金标题之揭秘淘宝分词算法】提到分词,有必要说下那个分词可以理解为多词分词,然而淘宝却不是这样去分词的。简单来说:淘宝的识别第一原则:中心词率先识别,且多半是不可分词!告诉大家一个小小的技巧,如何识别自己的宝贝标题的权重中心词

               

    百度分词算法

    一、关于中文分词:

      1.中文分词难度分析

      首先要说明下的是:普通用户的搜索与做SEO或者更大说熟悉网络搜索用户的搜索习惯是非常不一样的,而恰巧普通搜索用户是百度搜索的基础力量。 在开头 赘述 这一点是蒋鑫鹏为了表达其对于百度搜索算法中的中文分词的重视。因为,对于百度google这样的第二代搜索引擎来说,采用的检索技术主要是依靠关键字来 匹配的,而用户对于关键词的理解与机器程序对于关键词的理解是有很大距离的。

      在中文分词方面百度胜过了Google,这是baidu取胜google的关键因素之一,中文的分词比英文要复杂得多(同样与中文分词一样麻烦 的重要 语言 还有日语、韩语、俄语,这也是Google没办法在这几个地区取胜的原因之一),蒋鑫鹏在这里因为篇幅不做赘述,有兴趣的朋友可以研究一下拉丁语系(以英 文为例)的造句与中文造句的区别,中文造句不仅近义词很多,而且语序变化无常,副词太多(主谓宾之外的定状补,叹词等等)。

        简单举个例子“百度如何排名”“百度是如何排名的”“百度怎么排名”“百度是怎么排名的”“百度如何排位”“百度怎么排位”“百度按什么排 名”“百度 靠什 么排名”“百度的搜索是怎么排位的”……这几个短语短句至少都包含一个意思“百度搜索结果的排名是什么规则(原理)”,除此之外,每个句子都有其他的含 义,如这些句子还包含有“怎么做百度排名(实现这个目标的方法)”“百度是怎么进行搜索排名的(原理实现的过程)”……

      拿上面的例子来说:当用户输入以上短句时(大多数情况下,普通用户把百度当做是万能的,所以才搜索SEO开来这么不符合规则的搜索行为),百度要迅速的响应出用户需要的结果,这个时候,百度面临的核心问题是:

      A.首先要知道用户是要搜什么(语义分析,见“二”);

      B.其次因为百度的检索方式目前仍然以关键词匹配技术为主,所以要对用户的搜索进行分词(下一段将分析百度如何分词);

      C.然后百度要通过分词分出的结果,去数据库中检索匹配的快照;

      D.上一步只是检索出来,还要进行第四部的排名,这个时候已经不是挑战百度的难题了(虽然在SEO看来,这一步确实是非常艰难的)

      E.第五步要将得到的结果返回到搜索页面给用户使用,并且要完成其广告的投放(百度竞价广告),并要适当推广自己的产品(百度知道、百度文库……)写的有点乱,SEO顾问蒋鑫鹏在此致歉,没找到更好的陈述方式,望朋友们整理发扬光大。

      2.百度中文分词方式:

      百度对于中文的分词不仅是大量的用户搜索(这点不同于Google,百度毕竟是植根于中国文化的,对中文更了解),而且还有庞大的中文词典数据 库作支 撑, 并且动态加入了搜索热词,搜索行为造词等技术,【从近期百度算法的调整看,百度比以前更加尊重用户的搜索行为,就是用户的输入为首要,百度纠正次要,这点 那很重要哦】下面以实例来说,用户搜索“百度如何排名?”时的分词:

      A.自然分割:包括标点符号、空格引起的分割,这是首要因素,比如或者“百度 如何排名”这样的搜索行为会被百度首先划分为“百度”、“如何排名”,这一点是肯定的,要理解用户搜索的行为意图,首先是要尊重用户的搜索行为;(这是 SEO顾问蒋鑫鹏根据实战中的观察总结出的,做SEO的很多朋友可能没注意到,在此提个醒)

      B.中文词库分割:不难理解,“百度如何排名”将被分为“百度”“如何”“排名”这几个词,因为这是中文词典里存在的词,百度有庞大的中文词典库支撑,这个不是难度;

      C.分词组合分词:B中的分词显然是不够的,要更能理解用户意图,必须保证语义连贯,那么那三个词可以组合成“百度如何排名”;“百度如何”+ “排 名”; “百度排名”+“如何”;“如何排名”+“百度”以及这几个词颠倒的组合,重要程度按照顺序优先原则,紧接着是倒序和双向序列的分词组合,分析切分有个基 本的原则就是最少的切分。

      以上三点是通常意义上的分词,除此之外,还有更麻烦的分词需要百度处理,见后几点。

      D.分字:如果用户搜索“百 度 如 何 排名”的时候,百度也是无可奈何的,因为你不能判断出来用户就是在搜索“百度 如何 排名”,还得尊重用户搜索行为,所以,不得不进一步将中文词进行分字:“百”“度”“如”“何”“排名”,然后在进行组合分词,组成不同的词组去数据库中 匹配。

      E.别音字/错别字:如有人搜索“白度如何排名”实际上是误将“百度”打成“白度”,那么百度还要纠正这种错误,但近期的调整看,百度不像以前 通过词 库近 义匹配来进行纠错【而更多的是以用户搜索后浏览的行为积累的数据来为纠错做准备】(如搜索“白度”的很多用户最后花更多时间在“百度”关键词页面上,那么 百度以后对于“白度”的搜索纠错会偏重到“百度”上!

      当然,这个词是蒋鑫鹏举例说明,实际上百度搜索“白度”不是这样的,例子可以参看百度的“美规车”查看,百度会提示或者说试探你“您要找的是不 是: 美规车”),此外,百度对于纠错通过搜索下拉框相关词推荐、搜索页面底部“相关搜索”、百度知道(用户量很大,是百度搜索的重要补充)来进行纠错数据的统 计与纠错引导。

      F.新词:新词的来源一般有两种:a.近期流行语造成,这个百度的数据库会根据用户搜索行为积累的数据以及网络热词监测数据来进行调整补充到词库;b.语言新词/用户造词,这个主要是靠搜索行为累积的数据调整,也针对部分语言新词人工作补充。

      蒋鑫鹏再次补充说明一下,百度其实很累的,它对用户的每一次搜索行为都要进行统计(当然是机器程序记录的方式):一般主要记录搜索的关键词、到 访的页 面及 到访方式(一般都是链接)、各页面停留时间(之前不容易读取到,现在百度通过浏览cookis、百度账户、IP记录、百度统计【如果网站装了百度统计的程 序,实际上百度很聪明,用各种方式想尽办法进入到网站,比如最近流行的百度分享按钮,这个工具实际上就是最大的间谍】等大量辅助工具来统计),一般测算是 根据搜索后到访的百度提供的快照页面的浏览行为(先打开哪个,然后打开哪个,在哪里停留的时间长,最后从哪里离开百度来实现,百度对于一个网页对用户是否 有用的观点:在该页面停留时间最长,并最终在此页面浏览完毕后离开百度为首要标准,其次还有在这些页面的互动程度所起的因素。

      二、关于语义分析:

      其实这段要说的在上一段已经都提到,列出来无非是将“语义分析”这一检索行为与“分词”区别开来,语义分析与分词是相辅相成的,语义分析更多的 建立在 分词 与用户浏览行为习惯数据的研究结论基础之上,如前所述,百度通过各种方式大量统计用户的行为并针对这些行为及所用的关键词及输入方式索索的统计数据进行分 词的支撑与分词的匹配。

      毕竟,再怎么算,那么多网页、每天数十亿次的检索行为,百度还是难以计算出来的(百度正在通过不断改进方式及完善机器算法来努力实现这一浩大工 程), 目前 主要采用的是针对热门搜索的抽样统计与其他搜索的随机统计来实现搜索语义分析(此为SEO顾问蒋鑫鹏根据实战中的观察做的假想推断)。

        百度最难以捉摸透的与其说是排名算法,不如说是语义分析算法,因为与SEO搞不懂百度算法一样,百度同样搞不懂搜索用户的搜索意图(所以百度一直在研 究, 一直在调整,一直在完善,就像SEO一直在研究,一直在调整,一直在完善一样的道理)。捉摸不透是一个原因,更重要的是这些计算不仅仅是对于文字及分词、 匹配度的研究,更是通过统计学、线性数学、逻辑学、行为学、心理学等众多的学科的精华计算方法结合在一起设计出的算法结构,并不断修补完善的,说到这个算 法,百度有一个形容“海量基础算法”,更不用提每种算法的学科本身的难度了,这就是苦逼的SEO迟迟不能搞懂百度算法的根本原因,当然,作为苦逼的 SEO,蒋鑫鹏同样也是搞不懂的,如果能搞懂的,大多都是数学或计算机天才或顶尖人才,早都去搞自己的研究或者发明去了,还至于追在百度后面吹毛求疵?

      更何况,百度本身对于搜索结果的“人为干涉”及“垄断”都带来各种斥责,更何况SEO为了一己之利不断刷排名给用户推荐低质量的信息,那就更遭 懂得并 理解 搜索算法的牛人看不起了……所以看到这里,如果你觉得你很牛,就不要做SEO了,如果作为SEO你明白了作者蒋鑫鹏写此篇文章的意图,那你就站在SEM或 者网络运营、网络营销的高度来看待SEO,而不是为了半夜趴在电脑前发外链混营生而SEO。

      扯远了,回归正题,做不到像百度一样设计算法的那个能耐,如果说还能从语义分析中挖掘点对SEO有帮助的东西,那么蒋鑫鹏建议可以去研究研究你 正在做 的优 化的相关词的用户搜索习惯,比如,蒋鑫鹏最近给上海智宝美规车做网络运营服务期间,发现“美规车”这一词正在受到越来 越多的关注,而做这个词优化的很多SEO或者说站长都顶住“美规车”一个词做,而这个词用户搜索的时候,有可能衍生为“美规汽车”“美规汽车SUV”“美 规车SUV”“美规SUV”“美规车销售”“美规车经销”“美规车经销商”“美规汽车经销”“美规汽车销售”“美规汽车进口代理”等众多的派生词,甚至 “美规车哪里买”“上海哪儿销售美规车”这样的更具有成交意义的长尾关键词,如果理解用户的搜索意图,再针对性的做SEO,这样取得的效果会更好。

      三、关于关键词匹配度:

      1.关键词分词匹配重点次序:

      这是蒋鑫鹏根据SEO实际操作结合网友分享做的总结,精确度不高,但可作为参考。一般意义上的分词算法是“关键词比率”:计算该关键词在页面信 息中的 比 重,通常包含的参数有:title(网页标题)、meta description(网页描述/摘要)、meta keywords(网页关键词)、网页H1~H6标签、锚文本(按照重点程度及页面位置排序)、内容文本(突出程度如字体、大小、颜色、周围的背景或者说 文字等,一般的位置顺序是从左上到右下)、图片及其他页面文件的Html标记语言属性。

      2.关键词匹配度计算:

      分词后,要对短语中的关键词进行“索库”,如果某个词在短语中与其他词相关性不大,将去除匹配,但是其他词计算匹配度时任然作为字数计算。以 “百度如 何排 名”来分析:一般意义上,这个搜索短语被分为“百度如何排名”;“百度如何”+“排名”;“百度排名”+“如何”……:那么“百度如何排名”匹配度就是 100%,紧接着就是“百度排名如何”,“如何排名百度”,“如何百度排名”,“排名百度如何”,“排名如何百度”;“百度排名”的匹配度是1/3+1 /3=2/3;“如何排名”的匹配度是1/2;“百度”的匹配度是1/3……以上只是粗略的估算,具体的都多分词算法还要加入相关参数计算,如顺序优先 度,倒序优先度,双序优先度,最少化切词度……(具体的算法因蒋鑫鹏学识有限,恕不能分享,在此只是一个基本思路的分析,可以供朋友们参考,另外分词中含 有很多关于标点符号、空格、单字等的处理)

      3.title关键词匹配度:

      title中的关键词在title本身的分词匹配中的计算方式与2中提到的一样,蒋鑫鹏在此想说明两点:A.根据观察推断,百度收录快照后,对 快照的 存档 中应该已经做好可能的分词及匹配度的数据标注(如果不是这样,那么百度检索的效率不会有这么高)B.每一次用户的检索百度都要进行分词,并依分词的结果从 从档的快照中的分词标注中做最大化的匹配。

      另外,Title的公认长度一般认为是不超过80个字符(包含标点及空格,折合中文汉字约为40个字),但从百度检索结果的快照标题中看,对于 不同站 点百 度根据权重会有不同的限制,一般为60个字符,有的站能达到70个字符,超过的部分用“…”代替,但并不意味着百度不计算在内,以 “www.zhibaosuv.com”来说,蒋鑫鹏再添加标题的时候将“智宝美规车SUV”放到最后,但你百度“智宝美规车SUV”的时候现实的快照标 题可以正常显示“智宝美规车SUV”而将title超过显示的部分以段前段后省略的方式显示。

      一般,如果没有特殊必要,建议不要超过公认的80字符,否则,不仅稀释了关键词的匹配度,还会影响搜索引擎对快照的打分。

      【做title的技巧】,写到此,顺便分享下蒋鑫鹏的一点技巧,企业网站因为页面少,一般容易获得排名的主要是主页,所以主页的title一定 要精心 布 置,如果实在放不下的关键词放到description中靠前的位置,另外,建议将站点名称简写放在后面,以保证重点关键词靠前而获得较好的匹配度,站点 名称用“【】”起来,虽然浪费了4个字符,但是在搜索结果中会比较突出,能吸引用户的注意而提高网站知名度和进入率。

      顺便提下,蒋鑫鹏在操作中发现,如果头部标签更新频繁过度会被降权处理(一般头部修改后会进入快照观察期,搜索结果对于修改后的标题显示会延迟 1~3 周不 等,具体根据不同关键词在页面内容中的体现更新及外部链接锚文本中包含该关键词的更新度不等而延迟时间不等),头部标签一月内修改2次以上,百度会直接随 机抓取页面内的文本作为描述摘要。Google对于Title更新频繁的页面,会直接抓页面布局中重点体现的某段短语做标题。

      4.description关键词匹配度:

      与title的计算方式类似,只不过description不会被百度像title一样被分词,而只作为title中关键词和keyword中 的关键 词以 及给给页面带来流量较大的关键词的匹配计算,关键词在description中的匹配度按照顺序优先原则,以关键词在description总字符中的占 有比率及连贯度计算。

      description是对页面的摘要说明,做SEO的童鞋务必遵守规则,不要将无关信息或者说页面文本中不包含的关键词堆叠到此,以免降分。

      description公认的允许最大字符量为200,百度快照显示的一般为140字符左右,蒋鑫鹏建议不要超过160字符,因为这样不仅稀释 关键词 匹配 度,而且百度最近的算法调整,对description超出快照显示的部分将不再做关键词匹配。同样以智宝美规车来说 明,蒋鑫鹏将美规GMC放在描述摘要最好,最近算法调整后不做显示了(当然可能是个案,仅供参考)。

      5.keywords关键词匹配度:

      keywords对于百度来讲,貌似本身不作为匹配,但是有一点百度很在意:不要将页面没有的关键词加到keywords中,如果这样,有可能会被认为是在作弊,这点对于Google来说更是如此,Google对于keywords作弊比百度严格的多。

      keywords一般公认的不超过100字符,这点,蒋鑫鹏的理解是,对于Google来讲:keywords一定不要过多,要与页面匹配,一 般页面 能容 忍的关键词也就十多个到头;对于百度来讲,建议keywords的设计根据百度权重(可用站长工具或爱站网测试)关键词来设计,有权重的词,可以加到 keywords中。

      对于企业网站而言,因为Title和description限制而字数有限,无法容纳公司全称,这个时候可以考虑将公司全称及简称在keywords中体现一下,因为页面版权信息中一般会包含公司名和简称。

      6.页面内容中的关键词匹配度:

      页面内容不做分词计算,但标签中的分词和快照中存档的分词在页面所占比列计算中会对页面中包含的关键词进行匹配并计算次数及在整个页面字符中所占比例。

      页面的关键词重要程度首要的是H标签和其他重要的标签,当然在百度快照中主要是按照页面世家显示的文字为标准,一般链接锚文本中包含的关键词、 页面突 出位 置出现的关键词、以突出的方式(字体、颜色)展示出的关键词会比较重要,这点要根据具体页面作分析,SEO朋友们可以在检索关键词结果中直接查看百度快照 中显示的关键词匹配程度,黄色最高,其次为红色和蓝色、绿色。

      快照是存放在百度数据库中的静态网页,不是真实的网页,所以就有快照更新一说。从快照页面源代码中可以看出,百度快照中只是记载了页面的基本代码及文本文件,并为存储照片及其他文件,现实中的快照中的图片是从页面文件收录快照时记录的文件地址调用过来的。

      百度快照的存在,才是大家都关心百度快站更新的根本原因,因为如果快照不跟新,获得排名的机会就会变少,这个时候的你的网站的快照在百度快照数 据库中 就像 一个弃婴……写到此,作者蒋鑫鹏再次将自己的观察提醒一下:以前大家都认为静态页面更受搜索欢迎,随着2.0的不断发展及互联网社交化的趋势,似乎这点正 在被改写并朝着相反方向发展,静态页面、伪静态开始被搜索程序嫌弃……蒋鑫鹏是这样理解的,如果页面是静态的,那么搜索引擎更容易认为你的页面内容更新会 比较慢,这样自然影响收录频率,蜘蛛到访的频次也就降低了……

      四、关键词匹配操作——实例分析

      以上大致讲述了SEO蒋鑫鹏对于百度搜索中文分词及语义分析、关键词匹配的皮毛理解,下文通过实例重点讲一下如何让网页与关键词进行匹配。通 常,SEO一 般接到的任务都是客户/领导甩过来一个站,指定几个关键词,然后放手去做,除了在头部标签加上关键词,大量采集一些关键词相关的文章,剩下的貌似都是用各 种工具进行大量的“外部链接生产”工作了,一时间,包含“www.zhibaosuv.com”的乱七八糟的信息铺天盖地涌向各大论坛、博客、店铺、分类 信息……(当然,蒋鑫鹏也很低俗,做外链也大致是这样操作的,只不过基本不用工具,尽量减匹配度高相关性强的站点,针对性地发外链)。

      实际上,更好的SEO方式,是在进行排名优化操作前,根据用户的需求,做调查分析统计,然后依次配合客户其他需求,策划网站方案,将SEO的意 图在建 设网 站众志传媒出品)的过程中很好地融入,这样SEO做起来不累,也容易取得较为理想的效果,以上文中蒋鑫鹏提到的 服务中的客户上海智宝名车的例子来说,建站之初,众志传媒根据客户专营进口美规车SUV这一特点,通过百度搜索指数、Google关键词榜单、百度相关搜 索推荐、站长工具(tool.chinaz.com)进行过较为详尽的统计分析,最后根据客户主营的美规奔驰、美规宝马、美规奥迪、美规卡宴、美规路虎、 美规福特、美规丰田、美规林肯、美规GMC这些品牌车,确定了上述关键词(【特别说明,关键词的策划还要考虑百度竞价竞争程度、页面收录数量、首页结果页 的快照更新程度及百度全汇总,以此来确定难易程度,结合预算与工作量来确定】)。

      在网站设计工程中,众志传媒将产品展示这一栏目设计为“美规车频道”,并依次将上述关键词作为分类,并以下拉菜单的方式实现(蒋鑫鹏提醒:导航 条的锚 文本 出现的关键词是很重要的,而现在做优化,用户对于关键词数量要求越来越多,结合这一情况,蒋鑫鹏建议首选将导航做成页面左侧的列表通道【实战中发现很有 效,以三禾彩钢为例】,其次考虑希下拉表菜单及最近流行的页面底部行列式导航),在主页内容安排有限的前提下,在底部将关键词对应的栏目页URL做了辅助 导航,在首页文字信息中恰当地将锚文本融入,给主要的图片做了ALT属性等。

      在title设计中,当然“美规车”首选,其次根据关键词顺序排列优先的原则,将主页title设计为“美规车_美规奔驰,美规宝马,美规路 虎,美规 卡 宴,美规奥迪【智宝美规车SUV】”,因为其他几个关键词无法挤在title中,检索量及价值也不是很高,就放在了description中,并且在 description开头中加入“上海智宝名车公司,顶级美规车进口商,豪华名车SUV美规版经销专卖”,即显示了公司名称,同时又突出了公司特点并在 此体现了核心关键词“美规车”,接下来的“美规宝马X5X6,美规奔驰ML/GL系列,美规保时捷卡宴,美规奥迪Q7,美规路虎揽胜极光,美规林肯外交 官,美规福特,美规丰田,美规GMC。”是对重点产品型号关键词的体现,如“美规宝马X5”,“美规奥迪Q7”等。 毕竟页面的头部文件字符限制,导致很多有限关键词不能体现,对于规车这个网站,众志传媒做了内链的优化及各个页面的 代码优化工作,完善了站内所有页面的头部标签及页面的其他标签、链接,保证每个页面名称都不重复。以美规车频道 “http://www.zhibaosuv.com/Brand.asp”这个页面来说,title采用了“美规车,美规奔驰配置,豪华车SUV美规版 价格_智宝美规车频道”,核心关键词、页面重点关键词、站点名称及页面名称都在title中有良好的表现,并且栏目页面对应的产品子页面都是后台发布新产 品生成的,每个页面的标题及描述摘要都是动态调用了发布产品的名称几摘要。

      在网站运营中,未获得更多有价值的关键词的流量,智宝美规车新闻发布中,尽量采用原创的信息,并配合美观的图片及表格,以提升网页信息的可读 性,同 时,作 者不忘将关键词在文章中以突出显示的形式和加链接做成锚文本的形式表现,更有利于网站内部链接的建设及丰富,这在操作中获得明显的搜索表现。此外,新闻的 更新,边体重都是包含有限关键词的,在首页调用最新发布新闻标题的方式很好的保证了主页的更新度。

      写的有点累赘,百度的算法不是一两局说得清楚的,众志传媒网络营销顾问在整理发布的,也只是皮毛,从SEO的价值来讲,是一个理解SEO及百度关键词 匹配 计算法的分析思路,欢迎SEO童鞋们加入讨论,本文来自蒋鑫鹏的博客转载请以链接形式标明

     

     

    Baidu分词算法分析

    随 着搜索经济的崛起,人们开始越加关注全球各大搜索引擎的性能、技术和日流量。作为企业,会根据搜索引擎的知名度以及日流量来选择是否要投放广告等;作为 普通网民,会根据搜索引擎的性能和技术来选择自己喜欢的引擎查找资料;作为技术人员,会把有代表性的搜索引擎作为研究对象。 搜索引擎经济的崛起,又一次向人们证明了网络所蕴藏的巨大商机。网络离开了搜索将只剩下空洞杂乱的数据,以及大量等待去费力挖掘的金矿。


       但是,如何设计一个高效的搜索引擎?我们可以以百度所采取的技术手段来探讨如何设计一个实用的搜索引擎。搜索引擎涉及到许多技术点,比如查询处理,排序 算法,页面抓取算法,CACHE机制,ANTI-SPAM等等。这些技术细节,作为商业公司的搜索引擎服务提供商比如百度,GOOGLE等是不会公之于众 的。我们可以将现有的搜索引擎看作一个黑盒,通过向黑盒提交输入,判断黑盒返回的输出大致判断黑盒里面不为人知的技术细节。


      查询处理与分词是一个中文搜索引擎必不可少的工作,而百度作为一个典型的中文搜索引擎一直强调其“中文处理”方面具有其它搜索引擎所不具有的关键技术和优势。那么我们就来看看百度到底采用了哪些所谓的核心技术。

    查询处理

    1. 1

      用户向搜索引擎提交查询,搜索引擎一般在接受到用户查询后要做一些处理,然后在索引数据库里面提取相关的信息。那么百度在接受到用户查询后做了些什么工作呢?

    2. 2

       

    3. 3

      假设用户提交了不只一个查询串

      比如“信息检索 理论 工具”。那么搜索引擎首先做的是根据分隔符比如空格,标点符号,将查询串分割成若干子查询串,比如上面的查询就会被解析为:《信息检索,理论,工具》三个子字符串;这个道理简单,我们接着往下看。
        

    4. 4

      假设提交的查询有重复的内容,搜索引擎怎么处理呢?

      比 如查询“理论 工具 理论”,百度是将重复的字符串当作只出现过一次,也就是处理成等价的“理论 工具”,而GOOGLE显然是没有进行归并,而是将重复查询子串的权重增大进行处理。那么是如何得出这个结论的呢?我们可以将“理论 工具”提交给百度,返回341,000篇文档,大致看看第一页的返回内容。OK。继续,我们提交查询“理论 工具 理论”,在看看返回结果,仍然是那么多返回文档,当然这个不能说明太多问题,那看看第一页返回结果的排序,看出来了吗?顺序完全没有变化,而GOOGLE 则排序有些变动,这说明百度是将重复的查询归并成一个处理的,而且字符串之间的先后出现顺序基本不予考虑(GOOGLE是考虑了这个顺序关系的)。  

    5. 5

      假设提交的中文查询包含英文单词,搜索引擎是怎么处理的

      比 如查询”电影BT下载”,百度的方法是将中文字符串中的英文当作一个整体保留,并以此为断点将 中文切分开,这样上述的查询就切为《电影,BT,下载》,不论中间的英文是否一个字典里能查到的单词也好,还是随机的字符也好,都会当作一个 整体来对待。至于为什么,你用查询“电影dfdfdf下载”看看结果就知道了。当然如果查询中包含数字,也是如此办理。
        

    6. 6

      到目前为止,一切很简单,也很清楚,百度怎么处理用户查询的呢?

      归纳如下:首先根据分割符号将查询分开,然后看看是否有重复的字符串,如果有,就抛弃多余的,只保留一个,接着判断是否有英文或者数字,如果有的话,把英文或者数字当作一个整体保留并把前后的中文切开。
        

      END

     中文分词

    1. 1

      首先,讲讲百度的分词时机或者条件问题,是否是个中文字符串百度就拿来切一下呢?非也,要想被百度的分词程序荣幸的切割一下也是要讲条件的,哪能是个字符串就切割啊?你当百度是卖锯条的么?

    2. 2

       

    3. 3

      那么什么样的字符串才满足被切割的条件呢?

      简单说来,如果字符串只包含小于等于3个中文字符的话,那就保留不动,当字符串长度大于4个中文字符的时候,百度的分词程序才出马大干快上,把这个字符串肢解掉。


        

    4. 4

       

    5. 5

      怎么证明呢?

      我 们向百度提交“电影下载”,看看返回结果中标为红字的地方,不难看出来,查询已经被切割成《电影,下载》两个单词了,说明分词程序已经开工了,如果是比4 个中文字符更长的字符串,那分词程序就更不客气了,一定大卸八块而后快。我们来看看三个字符的情况,提交查询“当然择”,看起来这个查询不伦不类,那是因 为我希望看到这个字符串被切分为《当然,择》,返回结果365篇相关页面,翻到最后一页,发现标红的关键字都是” 当然择”连续出现的情况,好像没有切分,但是还不确定,那么再提交人工分好的查询“当然 择”看看,返回结果1,090,000篇,基本上可以确定没有进行分词了,当然另外一种解释是:对于三个字符先切分,然后将切分后的结果当作一个短语查 询,这样看到的效果和没有切分是相似的。但是我倾向于判断百度对于少于3个字符的串没有切分,奥卡姆不是说了么“如无必要,勿增实体”,干吗做无用功呢。 那么如果没有切分,会有一个随之而来的问题,怎么从索引库里面提取未切分的字符串呢?这牵扯到索引的问题,我觉得百度应该采取了两套索引机制,一种是按照 单词索引,一种是按照N-GRAM索引,至于索引的具体问题,以后在详细论述。

    6. 6

       

    7. 7

      下面我们看看百度是采取的何种分词算法

      现在分词算法已经算是比较成熟了,有简单的有复杂的,比如正向最大匹配,反向最大匹配,双向最大匹配,语言模型方 法,最短路径算法等等,有兴趣的可以用GOOGLE去搜索一下以增加理解。这里就不展开说了。但是要记住一点的是:判断一个分词系统好不好,关键看两点, 一个是消除歧义能力;一个是词典未登录词的识别比如人名,地名,机构名等。

    8. 8

      那么百度用的是什么方法?

      我的判断是用双向最大匹配算法。至于怎么推理得出的,让我们一步步来看。当然,这里首先有个假设,百度不会采取比较复杂的算法,因为考虑到速度问题。
        

      我 们提交一个查询“胡深东北京华烟云”,又一个不知所云的查询,尽管不知所云但是自有它的道理,我想看看百度的分词是如何消歧以及是否有词典未登录词的识 别的功能,如果是正向最大匹配算法的话,那么输出应该是:”胡深东/北京/华/烟云”,如果是反向最大匹配算法的话,那么输出应该是:”胡/胡/东北/京 华烟云”,我们看看百度的分词结果:”胡深东/北/京华烟云”,一个很奇怪的输出,跟我们的期望相差较多,但是从中我们可以获得如下信息:百度分词可以识 别人名,也可以识别”京华烟云”,这说明有词典未登录词的识别的功能,我们可以假设分词过程分为两个阶段:第一阶段,先查找一个特殊词典,这个词典包含一 些人名,部分地名以及一些普通词典没有的新词,这样首先将”胡深东”解析出来,剩下了字符串”北京华烟云”,而”北/京华烟云”,可以看作是反向最大匹配 的分词结果。这样基本说得通。为了证明这一点,我们提交查询”发胡深东北”,我们期望两种分词结果,一个是正向最大匹配《发胡,深,东北》, 一个是上述假设的结果《发,胡深东,北》,事实上百度输出是第二种情况,这样基本能确定百度分词采取了至少两个词典,一个是普通词典,一个是 专用词典(人名等)。而且是专用词典先切分,然后将剩余的片断交由普通词典来切分。

      继续测验,提交查询“古巴比伦理”,如果是正向最大匹 配,那么结果应该是《古巴比伦,理》,如果是反向最大匹配,那么结果应该是《古 巴,比,伦理》,事实上百度的分词结果是《古巴比伦,理》,从这个例子看,好像用了正向最大匹配算法;此外还有一些例子表明好像是使用 正向最大匹配的;但是且慢,我们看这个查询“北京华烟云”,正向最大匹配期望的结果是《北京,华,烟云》,而反向最大匹配期望的结果是 《北,京华烟云》,事实上百度输出的是后者,这说明可能采用的反向最大匹配;从这点我们可以猜测百度采用的是双向最大匹配分词算法,如果正向 和反向匹配分词结果一致当然好办,直接输出即可;但是如果两者不一致,正向匹配一种结果,反向匹配一种结果,此时该如何是好呢?从上面两个例子看,在这种 情况下,百度采取最短路径方法,也就是切分的片断越少越好,比如《古巴,比,伦理》和《古巴比伦,理》相比选择后者,《北 京,华,烟云》和《北,京华烟云》相比选择后者。还有类似的一些例子,这样基本可以解释这些输出结果。
        

    9. 9

      但是仍然遗留的问题是:如果正向反向分词不一致,而且最短路径也相同,那怎么办?输出正向的还是反向的结果?

      我 们再来看一个例子。提交查询“遥远古古巴比 伦”,这个查询被百度切分为《遥远,古古,巴比伦》,说明词典里面有”巴比伦”,但是是否有”古巴比伦”这个词汇不确定,此时看不出是正向切 分还是反向切分得出的结果,换查询为“遥远古巴比伦”,此时被切分为“遥远/古巴比伦”,这说明词典里面有”古巴比伦”这个词汇,这说明了“遥远古古巴比 伦”是正向最大匹配的结果。那为什么“遥远古古巴比伦”不会被反向切分为”遥/远古/古巴比伦”呢,百度的可能选择是这种情况下选择单字少的那组切分结 果。
        

    10. 10

      当然还可以继续追问:如果切分后单字也一样多,那怎么办?

    11. 11

      最后看一个例子,查询“王强大小:”,百度将其切分为“王/强大/小”,是正向切分的结果,如果是反向的会被切分为“王/强/大小”,这说明有歧义而且单字也相同则选择正向切分结果。
        

      OK,看到这里可能头已经有些晕了,最后总结一下百度的分词算法,当然里面还是有猜测的成分,算法如下:

    12. 12

      首先查询专用词典(人名,部分地名等),将专有名称切出,剩下的部分采取双向分词策略,如果两者切分结果相同,说明没有歧义,直接输出分词结果。如果不一致,则输出最短路径的那个结果,如果长度相同,则选择单字词少的那一组切分结果。如果单字也相同,则选择正向分词结果。

    13. 13

      百 度一直宣传自己在中文处理方面的优势,从上面看,分词算法并无特殊之处,消歧效果并不理想,即使百度采取比上述分词算法复杂些的算法也难以说成是优势, 如果说百度有优势的话,唯一的优势就是那个很大的专用词典,这个专用词典登录了人名(比如大长今),称谓(比如老太太),部分地名(比如阿联酋等),估计 百度采用学术界公布的比较新的命名实体识别算法从语料库里面不断识别出词典未登录词,逐渐扩充这个专门词典。如果这就是优势的话,那么这个优势能够保持多 久就是个很明显的问题。
        

    14. 14

      Spelling Checker拼写检查错误提示(以及拼音提示功能)
      拼写检查错误提示是搜索引擎都具备的一个功能,也就是说用户提交查询 给搜索引擎,搜索引擎检查看是否用户输入的拼写有错误,对于中文用户来说一般造成的错误是输入法造成的错误。那么我们就来分析看看百度是 怎么实现这一功能的。
        

      END

    我们分析拼写检查系统关注以下几个问题:

    1. 1

      系统如何判断用户的输入是有可能发生错误的查询呢?
       

    2. 2

      如果判断是可能错误的查询输入,如何提示正确的词汇呢?
        

    3. 3

      那么百度是如何做的呢?

      百 度判断用户输入是否错误的 标准,我觉得应该是查字典,如果发现字典里面不包含这个词汇,那么很有可能是个错误的输入,此时启动错误提示功能,这个很好判断,因为如果 是一个正常词汇的话,百度一般不会有错误提示,而你故意输入一个词典不可能包含的所谓词汇,此时百度一般会提示你正确的检索词汇。
        

    4. 4

      那么百度是怎么提示正确词汇的呢?

      很 明显是通过拼音的方式,比如我输入查询“ 制才”,百度提供的提示词汇为: “:制裁 质材 纸材“,都是同 音字。所以百度必然维持着一个同音词词典,里面保留着同音词信息,比如可能包含着下面这条词条: “ zhi cai à制裁,质材,纸材”,另外还有一 个标注拼音程序,现在能够看到的基本流程是: 用户输入“ 制才”,查词典,发现没有这个词汇,OK,启动标注拼音程序,将“ 制才”标注为拼音“zhi cai”,然后查找同音词词典,发现同音词“ 制裁,质材,纸材”,那么提示用户可能的正确拼写。
        

    5. 5

      整体流程看起来很简单,但是还有一些遗留 的小问题,比如是否将词表里面所有同音词都作为用户的提示信息呢?

      比 如某个拼音有10个同音词,是否都输出呢?百度并没有将所有同音词都输 出而是选择一定筛选标准,选择其中几个输出。怎么证明这一点?我们看看拼音“liu li”的同音词,紫光输入法提示同音词汇有“ 流丽 流离 琉璃 流利”4个,我们看看百度返回几个,输入“流厉”作为查询,这里是故意输入一个词典不包含的词汇,这样百度的拼写检查才开始工作,百度提示: “ 琉璃刘丽 刘莉 ”,这说明什么?说明不是所有同音词都输出,而是选择输出,那么选择的标准是什么?我能够猜测到的方法是对于用户查询LOG进行 统计,提取用户查询次数多的那些同音词输出,如果是这样的话,上面的例子说明用户搜索“琉璃”次数比其它的都要高些,次之是“ 刘丽”,再次是“ 刘莉”,看来大家都喜欢查询自己或者认识的人的名字。
        

    6. 6

      另外一个小问题:同音词词典包含2字词,3字词,那么是否包含4字词以及更长的词 条?是否包含一字词?

      这 里一字词好回答,不用测试也能知道肯定不包含,因为你输入一个字,谁知道是否是错误的呢?反正只要是汉字就能在词表 里面找到,所以没有判断依据。二字词是包含的,上面有例子,三字词也包含,比如查询 “中城药”百度错误提示:“中成药”,修改查询为“重城药”,还 是提示“中成药” ,再次修改查询 “重城要”,百度依然提示“中成药”。 那么4字词汇呢?
        百度还是会给你提示的,下面是个例子:
        输入:静华烟云 提示 京华烟云
        输入:静话烟云 提示 京华烟云
        输入:静话阎晕 提示 京华烟云
        

    7. 7

      那么更长的词汇是否提示呢?

      也提示,比如我输入: “落花世界有风军”,这个查询是什么意思,估计读过古诗的都知道,看看百度的提示“落花时节又逢君”,这说明什么?说 明同音词词典包含不同长度的同音词信息,另外也说明了百度的核心中文处理技术,也就是那个词典,还真挺大的。

      但是,如果用户输入的 查询由两个或者两个以上子字符串构成,那么百度的错误提示功能就罢工了,比如输入查询“哀体”,百度提示“艾提 挨踢”,但是。输入为 “我 哀体 ”,则没有任何错误提示。
        

    8. 8

      还有一个比较重要的问题:如果汉字是多音字那么怎么处理?

      百 度呢比较偷懒,它根本就没有对多音字做处理。我 们来看看百度的一个标注拼音的错误,在看这个错误前先看看对于多音字百度是怎么提示错误的,我们输入查询“俱长”,百度提示“剧场 局长”, “俱长“的拼音有两个:”ju zhang /ju chang“ ,可见如果是多音字则几种情况都提示。.现在我们来看看错误的情况, 我们输入查询”剧常“,百度 提示”:剧场局长“,提示为”剧场“当然好解释,因为是同音字,但是为什么 ”局长“也会被提示呢?这说明百度的同音字词典有错误,说明在”ju chang“这个词条里面包含”局长“这个错误的同音词。让我们顺藤摸瓜,这个错误又说明什么问题呢?说明百度的同音词典是自动生成的,而且没有 人工校对。还说明在自动生成同音词典的过程中,百度不是根据对一篇文章标注拼音然后在抽取词汇和对应的拼音信息获得的,而是完全按照某个 词典的词条来标注音节的,所以对于多音字造成的错误无法识别出来,如果是对篇章进行拼音标注,可能就不会出现这种很容易发现的错误标注。 当然还有另外一种解释,就是”局长“是故意被百度提示出来可能的正确提示词汇,因为考虑到南方人”zh“和 ”ch“等前后鼻音分不清么,那么是这 样的么?我们继续测试到底是何种情况。是百度有错误还是这是百度的先进的算法?
        

       

      我们考虑词汇”长大 “,故意错误输入为”赃大“,如果 百度考虑到了前后鼻音的问题,那么应该会提示”长大“,但是百度提示是”藏大“。这说明什么?说明百度并没有考虑前后鼻音问题,根本就是系统错 误。 我们输入查询”悬赏“,故意将之错误输入为”悬桑“,没有错误提示,说明确实没有考虑这种情况。前鼻音没有考虑,那么后鼻音考虑了么,我们 输入”:经常“,故意改为后鼻音 ”经缠“,百度提示为”经产 经忏“,还是没有考虑后鼻音。这基本可以确定是百度系统的错误导致。

      END

    根据以上推导, 我们可以得出如下结论:

    百 度是将分词词典里面每个词条利用拼音标注程序标注成拼音,然后形成同音词词典,所以两个词典是同样大的 ,而且这个词典也随着分词词典的增长而在不断增长。 至于标注过程中多音字百度没有考虑,如果是多音字就标注成多个发音组合,通过这种方式 形成同音词词典。这样的同音词词典显然包含着很多错误。

     


    最 后一个问题:百度对于英文进行拼写检查么?让我们试试看,输入查 询”china“,不错,搜到不少结果,专注中文搜索的百度还能搜索到英文,真是意外的惊喜。变换一下查询”chine“,会更加意外惊喜的给我们提 示”china“吗?百度提示的是: 吃呢持呢,原来是不小心触发了百度的拼音搜索功能了。那么拼音搜索和中文检查错误是否采用同一套同音词词典 呢,让我们来实验一下,搜索”rongji“,百度提示” 榕基 溶剂 容积“,OK,换个中文查询”容机“,百度提示” 榕基 溶剂容积“,看来使用的是同一套 同音词词典。也就是说百度的中文纠错和拼音检索使用的机制相同,中文纠错多了一道拼音注音的过程而已。难道这就是传说中那个百度的”事实 上是一个无比强大的拼音输入法“的拼音提示功能么? 

    最后让我们总结归纳一下百度的拼写检查系统:

    1. 1

      后台作业:
        

    2. 2

      前 面的文 章我们说过,百度分词使用的词典至少包含两个词典一个是普通词典,另外一个是专用词典(专名等),百度利用拼音标注程序依次扫描所有词典中 的每个词条,然后标注拼音,如果是多音字则把多个音都标上,比如”长大“,会被标注为”zhang da/chang da“两个词条。
        

    3. 3

      通过标注完的 词条,建立同音词词典,比如上面的”长大“,会有两个词条: zhang daà长大” , chang daà长大。
        

    4. 4

      利用用户查询LOG频率信息给予每个 中文词条一个权重;
        

    5. 5

      OK,同音词词典建立完成了,当然随着分词词典的逐步扩大,同音词词典也跟着同步扩大;
        

    6. 6

      拼写检查:  

    7. 7

      用户输入查询,如果是多个子字符串,不作拼写检查;
       

    8. 8

      对于用户查询,先查分词词典,如果发现有这个单词词条,OK, 不作拼写检查;
        

    9. 9

      如果发现词典里面不包含用户查询,启动拼写检查系统;首先利用拼音标注程序对用户输入进行拼音标注;

    10. 10

      对于标注好的拼音在同音词词典里面扫描,如果没有发现则不作任何提示;
        

    11. 11

      如果发现有词条,则按照顺序输出权重比较大的几个提 示结果;
        

    12. 12

      拼音提示: 

    13. 13

      对于用户输入的拼音在同音词词典里面扫描,如果没有发现则不作任何提示;
       

    14. 14

      如果 发现有词条,则按照顺序输出权重比较大的几个提示结果;
        

      上面说过,经过分析得出百度的分词系统采用双向最大匹配分词,但是后来发现推理过程中存在一个漏洞,而且推导出来的百度分词算法步骤还是过于繁琐,所以进一步进行分析,看看是否前面的推导有错误。

    15. 15

      那么以前的分析有什么漏洞呢?

      我 们推导百度分词有反向最大匹配的依据是百度将“北京华烟云”分词为《北,京华烟云》,从这里看好像采用了反向最大匹配,因为正向最大匹配的结果应该是《北 京,华,烟云》,但是由此就推论说百度采用了双向最大匹配还是太仓促了,前面文章我们也讲过,百度有两个词典,一个普通词典,一个专有词典,而且是专有词 典的词汇先切分,然后将剩余片断交给普通词典去切分。所以上面的“北京华烟云”之所以被切分成《北,京华烟云》,另外一个可能是:京华烟云这个词汇是在专 有词典里面存储的,所以先分析,这样得出“京华烟云”,剩下“北”,没什么好切分的,所以输出《北,京华烟云》。
       这里只是假设,那么是否确实 “京华烟云”在专有词典呢?我们再看一个例子“山东北京华烟云”,百度切分的结果是《山东,北,京华烟云》,如果“京华烟云”在普通词典,如果是反向切 分,那么结果应该是《山,东北,京华烟云》,如果是正向切分应该是《山东,北京,华,烟云》,无论如何都分不出《山东,北,京华烟云》。这说明什么?说明 “京华烟云”是在那个专有词典,所以先切分出“京华烟云”,然后剩下的“山东北”交由普通词典切分,明显是正向最大匹配的结果输出《山东,北》。当然按照 我们在第一篇文章的算法推导“山东北”的切分也会得出《山东,北》的结论,但是明显比正向最大匹配多几个判断步骤,既然效果一样,另外一个更加简洁的方法 也能说得通,那当然选择简便的方法了。所以初步判断百度采取的是正向最大匹配。
        

      我们继续测试采用何种分词算法,为了减少专有词 典首先分词造成的影响,那么查询里面不能出现相对特殊的词汇,构筑查询“天才能量级”,这里应该没有专有词典出现过的词汇,百度切分为《天才,能量, 级》,看来是正向最大匹配的结果。另外,如果所有查询词汇都出现在专有词典,那么采取的是何种方法?这样首先就得保证词汇都出现在专有词典,这么保证这一 点呢?我们构造查询“铺陈晓东方”,百度切分为《铺,陈晓东,方》,可以看出“陈晓东”是在专有词典的所以先切分出来。另外一个例子 “山东京城”,百度切分为《山东,京城》,说明“东京”是在普通词典的.OK,构造查询“陈晓东京华烟云”,通过前面分析可以看出两个词汇都在专有词典里 面,百度切分为《陈晓东,京华烟云》,说明对于专有词典词汇也是采取正向最大匹配或者双向最大匹配。那么使用反向最大匹配了吗?构造查询例子“陈晓东方不 败”,首先我们肯定“陈晓东”和“东方不败”都是在专有词典出现的,如果是正向切分,那么应该是《陈晓东,方,不败》或者《陈晓东,方,不,败》如果是反 向切分则是《陈,晓,东方不败》,可以看出百度的切分是《陈晓东,方,不败》或者《陈晓东,方,不,败》,说明采用的是正向最大匹配。通过分析,百度的词 典不包含“不败”这个单词,所以实际上百度的切分结果是《陈晓东,方,不,败》,很明显这和我们以前推导的算法是有矛盾的,所以以前的分析算法确实有问 题,所以结论是百度采取的是正向最大匹配算法。

      END

    注意事项

    • 重新归纳一下百度的分词系统:首先用专有词典采用最大正向匹配分词,切分出部分结果,剩余没有切分交给普通词典,同样采取正向最大匹配分词,最后输出结果。


    • 另外,GOOGLE也是采用正向最大匹配分词算法,不过好像没有那个专用词典,所以很多专名都被切碎了。从这点讲,GOOGLE在中文词典构建上比百度差些,还需要加把子力气才行,不过这也不是什么多难的

    •  

     
     
    展开全文
  • 本 Chat 首先简单介绍了自然语言处理中中文分词的概念和应用场景。然后通过两个简单的小例子展示了算法的步骤。接着编写了 Python 代码,并在《红楼梦》上做了测试。最后,总结了我在写代码中遇到的问题,以避免读者...

    本 Chat 首先简单介绍了自然语言处理中中文分词的概念和应用场景。然后通过两个简单的小例子展示了算法的步骤。接着编写了 Python 代码,并在《红楼梦》上做了测试。最后,总结了我在写代码中遇到的问题,以避免读者犯同样的错误。

    目录:

    分词算法的概念

    分词算法的应用

    具体算法

    Python 实现

    实例:《红楼梦》分词

    1. 分词算法的概念

    中文分词就是将中文语句中的词汇按照使用时的含义切分出来的过程,也就是将一个汉字序列切分成一个个有单独含义的词语。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂得多、困难得多。

    分词算法是自然语言处理(Nature Language Processing, NLP)中的基础。完整的中文自然语言处理过程一般包括以下五种中文处理核心技术:分词、词性标注、命名实体识别、依存句法分析、语义分析。

    2. 分词算法的应用

    下面从搜索引擎和机器翻译两方面介绍一下分词算法的应用。

    2.1 搜索引擎

    比如,在百度中搜索“科比詹姆斯”,在搜索之前,将“科比詹姆斯”这 5 个字拆分,变成了 “科比” 和 “詹姆斯”两个词,最终是以“科比” 和 “詹姆斯”两个词为关键词进行搜索,而不是直接搜索 5 个字。

    2.2 机器翻译

    比如,在有道词典中翻译“研究生命起源”。让机器直接翻译这6个字肯定是翻译不出来的,通过结果我们就可以看出,在翻译前,将“研究生命起源”6 个字拆分成了“研究”,“生命”和“起源”3 个词,再进行翻译之后组合在一起。

    2.3 手写英文

    书本上英文的单词之间总是存在空格,但是手写的英文之间的空格就没那么明显。这也是一个需要分词的场景。

    展开全文
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...

    本文的目标有两个:

    1、学会使用11大Java开源中文分词器

    2、对比分析11大Java开源中文分词器的分词效果

    本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。

    11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义一个统一的接口:

    复制代码

    /**
     * 获取文本的所有分词结果, 对比不同分词器结果
     * @author 杨尚川
     */
    public interface WordSegmenter {
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,去除重复
         */
        default public Set<String> seg(String text) {
            return segMore(text).values().stream().collect(Collectors.toSet());
        }
        /**
         * 获取文本的所有分词结果
         * @param text 文本
         * @return 所有的分词结果,KEY 为分词器模式,VALUE 为分词器结果
         */
        public Map<String, String> segMore(String text);
    }

    复制代码

     

    从上面的定义我们知道,在Java中,同样的方法名称和参数,但是返回值不同,这种情况不可以使用重载。

    这两个方法的区别在于返回值,每一个分词器都可能有多种分词模式,每种模式的分词结果都可能不相同,第一个方法忽略分词器模式,返回所有模式的所有不重复分词结果,第二个方法返回每一种分词器模式及其对应的分词结果。

    在这里,需要注意的是我们使用了Java8中的新特性默认方法,并使用stream把一个map的value转换为不重复的集合。

     

    下面我们利用这11大分词器来实现这个接口:

    1、word分词器

    复制代码

    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        for(SegmentationAlgorithm segmentationAlgorithm : SegmentationAlgorithm.values()){
            map.put(segmentationAlgorithm.getDes(), seg(text, segmentationAlgorithm));
        }
        return map;
    }
    private static String seg(String text, SegmentationAlgorithm segmentationAlgorithm) {
        StringBuilder result = new StringBuilder();
        for(Word word : WordSegmenter.segWithStopWords(text, segmentationAlgorithm)){
            result.append(word.getText()).append(" ");
        }
        return result.toString();
    }

    复制代码

     

    2、Ansj分词器

    复制代码

    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
    
        StringBuilder result = new StringBuilder();
        for(Term term : BaseAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("BaseAnalysis", result.toString());
    
        result.setLength(0);
        for(Term term : ToAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("ToAnalysis", result.toString());
    
        result.setLength(0);
        for(Term term : NlpAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("NlpAnalysis", result.toString());
    
        result.setLength(0);
        for(Term term : IndexAnalysis.parse(text)){
            result.append(term.getName()).append(" ");
        }
        map.put("IndexAnalysis", result.toString());
    
        return map;
    }

    复制代码

     

    3、Stanford分词器

    复制代码

    private static final StanfordCoreNLP CTB = new StanfordCoreNLP("StanfordCoreNLP-chinese-ctb");
    private static final StanfordCoreNLP PKU = new StanfordCoreNLP("StanfordCoreNLP-chinese-pku");
    private static final PrintStream NULL_PRINT_STREAM = new PrintStream(new NullOutputStream(), false);
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("Stanford Beijing University segmentation", seg(PKU, text));
        map.put("Stanford Chinese Treebank segmentation", seg(CTB, text));
        return map;
    }
    private static String seg(StanfordCoreNLP stanfordCoreNLP, String text){
        PrintStream err = System.err;
        System.setErr(NULL_PRINT_STREAM);
        Annotation document = new Annotation(text);
        stanfordCoreNLP.annotate(document);
        List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
        StringBuilder result = new StringBuilder();
        for(CoreMap sentence: sentences) {
            for (CoreLabel token: sentence.get(CoreAnnotations.TokensAnnotation.class)) {
                String word = token.get(CoreAnnotations.TextAnnotation.class);;
                result.append(word).append(" ");
            }
        }
        System.setErr(err);
        return result.toString();
    }

    复制代码

     

    4、FudanNLP分词器

    复制代码

    private static CWSTagger tagger = null;
    static{
        try{
            tagger = new CWSTagger("lib/fudannlp_seg.m");
            tagger.setEnFilter(true);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("FudanNLP", tagger.tag(text));
        return map;
    }

    复制代码

     

    5、Jieba分词器

    复制代码

    private static final JiebaSegmenter JIEBA_SEGMENTER = new JiebaSegmenter();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("INDEX", seg(text, SegMode.INDEX));
        map.put("SEARCH", seg(text, SegMode.SEARCH));
        return map;
    }
    private static String seg(String text, SegMode segMode) {
        StringBuilder result = new StringBuilder();                
        for(SegToken token : JIEBA_SEGMENTER.process(text, segMode)){
            result.append(token.word.getToken()).append(" ");
        }
        return result.toString(); 
    }

    复制代码

     

    6、Jcseg分词器

    复制代码

    private static final JcsegTaskConfig CONFIG = new JcsegTaskConfig();
    private static final ADictionary DIC = DictionaryFactory.createDefaultDictionary(CONFIG);
    static {
        CONFIG.setLoadCJKSyn(false);
        CONFIG.setLoadCJKPinyin(false);
    }
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
    
        map.put("复杂模式", segText(text, JcsegTaskConfig.COMPLEX_MODE));
        map.put("简易模式", segText(text, JcsegTaskConfig.SIMPLE_MODE));
    
        return map;
    }
    private String segText(String text, int segMode) {
        StringBuilder result = new StringBuilder();        
        try {
            ISegment seg = SegmentFactory.createJcseg(segMode, new Object[]{new StringReader(text), CONFIG, DIC});
            IWord word = null;
            while((word=seg.next())!=null) {         
                result.append(word.getValue()).append(" ");
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    复制代码

     

    7、MMSeg4j分词器

    复制代码

    private static final Dictionary DIC = Dictionary.getInstance();
    private static final SimpleSeg SIMPLE_SEG = new SimpleSeg(DIC);
    private static final ComplexSeg COMPLEX_SEG = new ComplexSeg(DIC);
    private static final MaxWordSeg MAX_WORD_SEG = new MaxWordSeg(DIC);
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put(SIMPLE_SEG.getClass().getSimpleName(), segText(text, SIMPLE_SEG));
        map.put(COMPLEX_SEG.getClass().getSimpleName(), segText(text, COMPLEX_SEG));
        map.put(MAX_WORD_SEG.getClass().getSimpleName(), segText(text, MAX_WORD_SEG));
        return map;
    }
    private String segText(String text, Seg seg) {
        StringBuilder result = new StringBuilder();
        MMSeg mmSeg = new MMSeg(new StringReader(text), seg);        
        try {
            Word word = null;
            while((word=mmSeg.next())!=null) {       
                result.append(word.getString()).append(" ");
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    复制代码

     

    8、IKAnalyzer分词器

    复制代码

    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
    
        map.put("智能切分", segText(text, true));
        map.put("细粒度切分", segText(text, false));
    
        return map;
    }
    private String segText(String text, boolean useSmart) {
        StringBuilder result = new StringBuilder();
        IKSegmenter ik = new IKSegmenter(new StringReader(text), useSmart);        
        try {
            Lexeme word = null;
            while((word=ik.next())!=null) {          
                result.append(word.getLexemeText()).append(" ");
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();
    }

    复制代码

     

    9、Paoding分词器

    复制代码

    private static final PaodingAnalyzer ANALYZER = new PaodingAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
    
        map.put("MOST_WORDS_MODE", seg(text, PaodingAnalyzer.MOST_WORDS_MODE));
        map.put("MAX_WORD_LENGTH_MODE", seg(text, PaodingAnalyzer.MAX_WORD_LENGTH_MODE));
        
        return map;
    }
    private static String seg(String text, int mode){
        ANALYZER.setMode(mode);
        StringBuilder result = new StringBuilder();
        try {
            Token reusableToken = new Token();
            TokenStream stream = ANALYZER.tokenStream("", new StringReader(text));
            Token token = null;
            while((token = stream.next(reusableToken)) != null){
                result.append(token.term()).append(" ");
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return result.toString();          
    }

    复制代码

     

    10、smartcn分词器

    复制代码

    private static final SmartChineseAnalyzer SMART_CHINESE_ANALYZER = new SmartChineseAnalyzer();
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("smartcn", segText(text));
        return map;
    }
    private static String segText(String text) {
        StringBuilder result = new StringBuilder();
        try {
            TokenStream tokenStream = SMART_CHINESE_ANALYZER.tokenStream("text", new StringReader(text));
            tokenStream.reset();
            while (tokenStream.incrementToken()){
                CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
                result.append(charTermAttribute.toString()).append(" ");
            }
            tokenStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return result.toString();
    }

    复制代码

     

    11、HanLP分词器

    复制代码

    private static final Segment N_SHORT_SEGMENT = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
    private static final Segment DIJKSTRA_SEGMENT = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
    @Override
    public Map<String, String> segMore(String text) {
        Map<String, String> map = new HashMap<>();
        map.put("标准分词", standard(text));
        map.put("NLP分词", nlp(text));
        map.put("索引分词", index(text));
        map.put("N-最短路径分词", nShort(text));
        map.put("最短路径分词", shortest(text));
        map.put("极速词典分词", speed(text));
        return map;
    }
    private static String standard(String text) {
        StringBuilder result = new StringBuilder();
        StandardTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String nlp(String text) {
        StringBuilder result = new StringBuilder();
        NLPTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String index(String text) {
        StringBuilder result = new StringBuilder();
        IndexTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String speed(String text) {
        StringBuilder result = new StringBuilder();
        SpeedTokenizer.segment(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String nShort(String text) {
        StringBuilder result = new StringBuilder();
        N_SHORT_SEGMENT.seg(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }
    private static String shortest(String text) {
        StringBuilder result = new StringBuilder();
        DIJKSTRA_SEGMENT.seg(text).forEach(term->result.append(term.word).append(" "));
        return result.toString();
    }

    复制代码

     

    现在我们已经实现了本文的第一个目的:学会使用11大Java开源中文分词器。

    最后我们来实现本文的第二个目的:对比分析11大Java开源中文分词器的分词效果,程序如下:

    复制代码

    public static Map<String, Set<String>> contrast(String text){
        Map<String, Set<String>> map = new LinkedHashMap<>();
        map.put("word分词器", new WordEvaluation().seg(text));
        map.put("Stanford分词器", new StanfordEvaluation().seg(text));
        map.put("Ansj分词器", new AnsjEvaluation().seg(text));
        map.put("HanLP分词器", new HanLPEvaluation().seg(text));
        map.put("FudanNLP分词器", new FudanNLPEvaluation().seg(text));
        map.put("Jieba分词器", new JiebaEvaluation().seg(text));
        map.put("Jcseg分词器", new JcsegEvaluation().seg(text));
        map.put("MMSeg4j分词器", new MMSeg4jEvaluation().seg(text));
        map.put("IKAnalyzer分词器", new IKAnalyzerEvaluation().seg(text));
        map.put("smartcn分词器", new SmartCNEvaluation().seg(text));
        return map;
    }
    public static Map<String, Map<String, String>> contrastMore(String text){
        Map<String, Map<String, String>> map = new LinkedHashMap<>();
        map.put("word分词器", new WordEvaluation().segMore(text));
        map.put("Stanford分词器", new StanfordEvaluation().segMore(text));
        map.put("Ansj分词器", new AnsjEvaluation().segMore(text));
        map.put("HanLP分词器", new HanLPEvaluation().segMore(text));
        map.put("FudanNLP分词器", new FudanNLPEvaluation().segMore(text));
        map.put("Jieba分词器", new JiebaEvaluation().segMore(text));
        map.put("Jcseg分词器", new JcsegEvaluation().segMore(text));
        map.put("MMSeg4j分词器", new MMSeg4jEvaluation().segMore(text));
        map.put("IKAnalyzer分词器", new IKAnalyzerEvaluation().segMore(text));
        map.put("smartcn分词器", new SmartCNEvaluation().segMore(text));
        return map;
    }
    public static void show(Map<String, Set<String>> map){
        map.keySet().forEach(k -> {
            System.out.println(k + " 的分词结果:");
            AtomicInteger i = new AtomicInteger();
            map.get(k).forEach(v -> {
                System.out.println("\t" + i.incrementAndGet() + " 、" + v);
            });
        });
    }
    public static void showMore(Map<String, Map<String, String>> map){
        map.keySet().forEach(k->{
            System.out.println(k + " 的分词结果:");
            AtomicInteger i = new AtomicInteger();
            map.get(k).keySet().forEach(a -> {
                System.out.println("\t" + i.incrementAndGet()+ " 、【"   + a + "】\t" + map.get(k).get(a));
            });
        });
    }
    public static void main(String[] args) {
        show(contrast("我爱楚离陌"));
        showMore(contrastMore("我爱楚离陌"));
    }

    复制代码

     

    运行结果如下:

    复制代码

    ********************************************
    word分词器 的分词结果:
        1 、我 爱 楚离陌 
    Stanford分词器 的分词结果:
        1 、我 爱 楚 离陌 
        2 、我 爱 楚离陌 
    Ansj分词器 的分词结果:
        1 、我 爱 楚离 陌 
        2 、我 爱 楚 离 陌 
    HanLP分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    smartcn分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    FudanNLP分词器 的分词结果:
        1 、我 爱楚离陌
    Jieba分词器 的分词结果:
        1 、我爱楚 离 陌 
    Jcseg分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    MMSeg4j分词器 的分词结果:
        1 、我爱 楚 离 陌 
    IKAnalyzer分词器 的分词结果:
        1 、我 爱 楚 离 陌 
    ********************************************
    ********************************************
    word分词器 的分词结果:
        1 、【全切分算法】    我 爱 楚离陌 
        2 、【双向最大最小匹配算法】    我 爱 楚离陌 
        3 、【正向最大匹配算法】    我 爱 楚离陌 
        4 、【双向最大匹配算法】    我 爱 楚离陌 
        5 、【逆向最大匹配算法】    我 爱 楚离陌 
        6 、【正向最小匹配算法】    我 爱 楚离陌 
        7 、【双向最小匹配算法】    我 爱 楚离陌 
        8 、【逆向最小匹配算法】    我 爱 楚离陌 
    Stanford分词器 的分词结果:
        1 、【Stanford Chinese Treebank segmentation】    我 爱 楚离陌 
        2 、【Stanford Beijing University segmentation】    我 爱 楚 离陌 
    Ansj分词器 的分词结果:
        1 、【BaseAnalysis】    我 爱 楚 离 陌 
        2 、【IndexAnalysis】    我 爱 楚 离 陌 
        3 、【ToAnalysis】    我 爱 楚 离 陌 
        4 、【NlpAnalysis】    我 爱 楚离 陌 
    HanLP分词器 的分词结果:
        1 、【NLP分词】    我 爱 楚 离 陌 
        2 、【标准分词】    我 爱 楚 离 陌 
        3 、【N-最短路径分词】    我 爱 楚 离 陌 
        4 、【索引分词】    我 爱 楚 离 陌 
        5 、【最短路径分词】    我 爱 楚 离 陌 
        6 、【极速词典分词】    我 爱 楚 离 陌 
    smartcn分词器 的分词结果:
        1 、【smartcn】    我 爱 楚 离 陌 
    FudanNLP分词器 的分词结果:
        1 、【FudanNLP】    我 爱楚离陌
    Jieba分词器 的分词结果:
        1 、【SEARCH】    我爱楚 离 陌 
        2 、【INDEX】    我爱楚 离 陌 
    Jcseg分词器 的分词结果:
        1 、【简易模式】    我 爱 楚 离 陌 
        2 、【复杂模式】    我 爱 楚 离 陌 
    MMSeg4j分词器 的分词结果:
        1 、【SimpleSeg】    我爱 楚 离 陌 
        2 、【ComplexSeg】    我爱 楚 离 陌 
        3 、【MaxWordSeg】    我爱 楚 离 陌 
    IKAnalyzer分词器 的分词结果:
        1 、【智能切分】    我 爱 楚 离 陌 
        2 、【细粒度切分】    我 爱 楚 离 陌 
    ********************************************

    复制代码

     

    标签: 算法分词开源

    展开全文
  • 本文的目标有两个: ...本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不...
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...
  • 首先,我们按照中文自然语言处理流程的第一步获取语料,然后重点进行中文分词的学习。中文分词有很多种,常见的比如有中科院计算所 NLPIR、哈工大 LTP、清华大学 THULAC 、斯坦福分词器、Hanlp 分词器、jieba 分词、...
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...
  • 最近在做建筑行业相关项目,遇到一个应用场景是解析材料名称。由于输入数据中材料名称非常不规范,而且数量量又非常大,所以处理起来比较困难。 名称不规范意思是,比如标准材料叫:“圆钢”,材料中出现...
  • 本文的目标有两个: 1、学会使用10大Java开源中文...本文给出了10大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 10大Java开源中文分词器,
  • 基于CRF的中文分词

    2019-08-02 06:44:16
    CRF简介 ...CRF由John Lafferty最早用于NLP技术领域,其在NLP技术领域中主要用于文本标注,并有多种应用场景,例如: 分词(标注字的词位信息,由字构词) 词性标注(标注分词的词性,例如:名...
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...
  • 本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。 11大Java开源中文分词器,不同的分词器有不同的用法,定义的接口也不一样,我们先定义...
  • 1、学会使用11大Java开源中文分词器2、对比分析11大Java开源中文分词器的分词效果本文给出了11大Java开源中文分词的使用方法以及分词结果对比代码,至于效果哪个好,那要用的人结合自己的应用场景自己来判断。...

空空如也

空空如也

1 2 3 4 5 6
收藏数 120
精华内容 48
热门标签
关键字:

中文分词的应用场景