搜索绝对不仅仅是搭起框架,跑出结果就完成的工作,之后分词、排序等等的优化才是重头戏。

先交代下背景:这个搜索是我一个人负责搭建并优化的项目,主要索引对象为歌曲、歌手MV等等。

使用技术:Lucene、IK_Analyzer

既然这篇博客是关于中文分词的优化,那么先看我现在的搜索有什么问题存在:

分词不准确

(1)如果搜索"没有你陪伴"时,排序在前面的歌曲为"陪伴",而本应排第一的"没有你陪伴真的好孤单"这首歌却在后面几页(因为没有"没有你陪伴"这首歌)。

(2)再比如搜索"阿哥阿妹不分手"这首歌时,并不能搜出"阿哥阿妹不分离"这首歌。

(3)如果搜索"没有你陪伴真的好孤单",那么包含"陪伴"、"没有"、"你"等词的歌曲都会被显示,导致显示结果过多(因为没有你陪伴真的好孤单本身就是一个歌名)。

现在最主要的问题就是这三类。那么就针对这三类开始优化吧:

关于分词的问题,因为使用的是Ik分词器,本身自带词库,但是对于我的搜索来说,绝大多数搜索是针对歌曲和歌手进行搜索,那么很自然的想到IK的扩展词库:ext.dic 可以简单的将所有歌曲和歌手添加进扩展词库,并且使用IK的最大细粒度进行切分,这样当用户搜索完整的歌曲名和歌手名时,可以得到最准确的分词。

这里需要注意,因为很多歌曲名带有字符和其它语言,比如上述提到的 《 和 日语英文夹杂的情况,如果不经处理直接将"母亲日剧《排球女将》插曲"插入扩展词,其实并没有什么卵用,为什么呢? 因为基本没有用户会完整的在搜索框中输入" 母亲日剧《排球女将》插曲",更多的用户在查找这首歌时,会输入"母亲"、"日剧插曲"、"排球女将"或"排球女将插曲"等等

注意到一个共同点,中国用户一般不会去搜索中文与符号夹杂、中文与英文夹杂(分情况,在搜美剧或英文歌时比较多),一般都是只搜中文

那么很自然的想到去除歌曲名和歌手名中的特殊字符,只留下中文加入到扩展词中(等于是用英文或字符将标题分割成几个独立的词加入到扩展词库中)

如:"日剧《排球女将》插曲"就拆分成:"日剧"、"排球女将"和"插曲"加入到扩展词库中。

代码如下:

    public Set<String> extWordProcesse(String extWord) {
if(extWord == null)
return null;
char[] array = extWord.toCharArray();
Set<String> result = new HashSet<String>();
String subString;
Integer start = 0;
while(start < array.length) {
for(int i=start;i<array.length;i++) {
if(!String.valueOf(array[i]).matches("[\\u4E00-\\u9FA5]+")) {
if(start < i) {
subString = extWord.substring(start, i);
if(subString.length() != 1)
result.add(subString);
start = i + 1;
} else if(start == i) {
start++;
}
break;
} else {
if(i == array.length - 1) {
subString = extWord.substring(start, i + 1);
if(subString.length() != 1)
result.add(subString);
start = i + 1;
}
}
}
} return result;
}

下面是添加扩展词前后分词的对比(使用最大粒度分词):用"没有你孤单真的好孤独"作为例子

加入扩展词前:

0-2 : 没有 :     CN_WORD

2-3 : 你 :     CN_WORD

3-5 : 陪伴 :     CN_WORD

5-7 : 真的 :     CN_WORD

7-10 : 好孤单 :     CN_WORD

加入扩展词后使用最大粒度分词:

0-10 : 没有你陪伴真的好孤单 :     CN_WORD

那么如果用户输入搜索"没有你陪伴真的好孤单"时,因为有完全一致的歌曲名与关键词匹配,那么只需要返回完全匹配的记录,而像包括"没有"、"你"、"陪伴"等等的记录可以不显示,因为这个时候用户的搜索是目的性非常明确的

这样通过添加歌曲名和歌手名到扩展词库中,可以解决分词问题下的(3)小点。

而分词问题下剩余的(1)(2)问题可以归为一类,有点类似搜索校正的感觉,(1)是前缀匹配,(2)是拼写纠错。

其实这两个问题都可以通过分词来解决:

先看下在加入扩展词后用最大粒度分词的结果:

0-7 : 阿哥阿妹不分手 :     CN_WORD
0-3 : 没有你 :     CN_WORD

3-5 : 陪伴 :     CN_WORD

但是上面刚才提到了,加入扩展词后用最大粒度分词,"没有你陪伴真的好孤单"分词时将会作为一个整体,并不会分成"没有你","陪伴"。那么搜索"没有你陪伴时"并不会命中"没有你陪伴真的好孤单",那么怎么办呢?

我们知道Lucene,索引和搜索时,都需要分词,索引时是分词后构建倒排索引,搜索时分词后进行空间向量的计算得分。

那么我们可以索引时不使用最大粒度,而使用最小粒度分词。

什么意思呢? 先看实例:

"没有你陪伴真的好孤单"最小粒度分词的结果:

0-3 : 没有你 :     CN_WORD

0-2 : 没有 :     CN_WORD

1-5 : 有你陪伴 :     CN_WORD

1-4 : 有你陪 :     CN_WORD

1-3 : 有你 :     CN_WORD

1-2 : 有 :     CN_WORD

2-3 : 你 :     CN_WORD

3-5 : 陪伴 :     CN_WORD

这样是不是明白很多了? 如果我们使用最小粒度分词的话,那么就可以解决(1)(2)问题了,但是这样又不能解决(3)问题了,因为如果索引和搜索时都使用最小粒度分词,那么搜索出来的结果会很多,影响用户体验和搜索速度

所以(1)(2)和(3)是对立的,解决其中一个,另外一个变会出现,那怎么办呢? 最简单的就是分情况处理。

我们可以看到,如果用户搜索的一个关键词key,如果完全匹配歌曲名或者歌手名时,搜索时应该使用最大粒度分词,以减少不想关的搜索结果,如果不完全匹配,那么需要使用最小粒度分词,用以匹配所有可能的结果。当然,索引永远是使用最小粒度分词。

那么我的做法是,将所有的歌曲名和歌手名经过上述代码处理后,加入到一个Set中,每次搜索时,对关键字在Set中查找,如果存在,那么说明时完全匹配歌曲或歌手的,使用最大粒度分词,如果不存在,那么不匹配。使用最小粒度匹配。

上述的最大粒度最小粒度,IK分词器已经提供了相关实现:

在IKAnalyzer的构造函数中有一个boolean参数,true为最大粒度,false为最小粒度:

new IKAnalyzer(false)

我的搜索优化记录(一):中文分词优化IK Analyzer的更多相关文章

  1. 转:solr6.0配置中文分词器IK Analyzer

    solr6.0中进行中文分词器IK Analyzer的配置和solr低版本中最大不同点在于IK Analyzer中jar包的引用.一般的IK分词jar包都是不能用的,因为IK分词中传统的jar不支持s ...

  2. 我与solr(六)--solr6.0配置中文分词器IK Analyzer

    转自:http://blog.csdn.net/linzhiqiang0316/article/details/51554217,表示感谢. 由于前面没有设置分词器,以至于查询的结果出入比较大,并且无 ...

  3. 轻量级的中文分词工具包 - IK Analyzer

    IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本.最初,它是以开源项目Luence为应用 ...

  4. ElasticSearch7.3学习(十五)----中文分词器(IK Analyzer)及自定义词库

    1. 中文分词器 1.1 默认分词器 先来看看ElasticSearch中默认的standard 分词器,对英文比较友好,但是对于中文来说就是按照字符拆分,不是那么友好. GET /_analyze ...

  5. 沉淀再出发:ElasticSearch的中文分词器ik

    沉淀再出发:ElasticSearch的中文分词器ik 一.前言   为什么要在elasticsearch中要使用ik这样的中文分词呢,那是因为es提供的分词是英文分词,对于中文的分词就做的非常不好了 ...

  6. ElasticSearch搜索引擎安装配置中文分词器IK插件

    近几篇ElasticSearch系列: 1.阿里云服务器Linux系统安装配置ElasticSearch搜索引擎 2.Linux系统中ElasticSearch搜索引擎安装配置Head插件 3.Ela ...

  7. 如何在Elasticsearch中安装中文分词器(IK)和拼音分词器?

    声明:我使用的Elasticsearch的版本是5.4.0,安装分词器前请先安装maven 一:安装maven https://github.com/apache/maven 说明: 安装maven需 ...

  8. 如何给Elasticsearch安装中文分词器IK

    安装Elasticsearch安装中文分词器IK的步骤: 1. 停止elasticsearch 2.2的服务 2. 在以下地址下载对应的elasticsearch-analysis-ik插件安装包(版 ...

  9. ElasticSearch 中文分词插件ik 的使用

    下载 IK 的版本要与 Elasticsearch 的版本一致,因此下载 7.1.0 版本. 安装 1.中文分词插件下载地址:https://github.com/medcl/elasticsearc ...

随机推荐

  1. 我的项目:一个chrome插件的诞生记,名字叫jumper

    选课是个问题,为了选课,便有了以下的故事. 最开始,萌生想法于2013年7月. 接着网上了解了chrome的结构知识,却发现例子是假的. 幸好有之前师兄的一个同功能插件开源,但代码写得很乱,我喜欢逻辑 ...

  2. 3 - testng.xml

    TestNG的调用有以下几种方式: testng.xml ant 命令行 这部分主要介绍testng.xml的格式. 当前testng.xml的DTD(文档类型定义(Document Type Def ...

  3. java中的异常结构

    1.基类为Throwable. 2.Error和Exception分别继承Throwable. 3.Error类异常描述了Java运行系统中的内部错误以及资源耗尽的情形.应用程序不应该抛出这种类型的对 ...

  4. meta标签常用属性整理

    在segmentfault看到这篇文章,觉得整理的很详细,所以转载过来和大家分享一下. 原文地址:http://segmentfault.com/blog/ciaocc/119000000240791 ...

  5. rel=nofollow 是什么意思

    nofollow是什么意思? nofollow是html标签的一个属性值,Google推荐使用nofollow,告诉机器(爬虫)无需追踪目标页,是指禁止蜘蛛爬行和传递权重,但是如果你是通过sitema ...

  6. WordPress批量修改文章内容、URL链接、文章摘要

    通过SQL语句来批量修改wordpress博客内容,文章中所有语句都使用默认的wp_表前缀,如果您的数据表前缀不是wp_则需要在语句中作相应更改. 方法/步骤   批量修改文章内容 如果您想替换之前写 ...

  7. Python学习的一些好资料

    教程: 1. 廖雪峰的Python教程:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a0 ...

  8. python自动开发之第十八天

    一.JS正则 test - 判断字符串是否符合规定的正则 rep = /\d+/; rep.test("asdfoiklfasdf89asdfasdf") # true rep = ...

  9. Vim及VimScript资料总结《转载》

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   Vim教程 入门 Vim 实用技术 Learning the vi and Vim Editors A Byte of ...

  10. iOS开发工程师笔试题

    iOS开发工程师笔试题 1.   Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么? Object-c的类不可以多重继承:可以 ...