业务需求

  1. 实现搜索引擎前缀搜索功能(中文,拼音前缀查询及简拼前缀查询功能)

  2. 实现摘要全文检索功能,及标题加权处理功能(按照标题权值高内容权值相对低的权值分配规则,按照索引的相关性进行排序,列出前20条相关性最高的文章)

前缀搜索

中文搜索:

  1. 搜索“刘”,匹配到“刘德华”、“刘斌”、“刘德志”

  2. 搜索“刘德”,匹配到“刘德华”、“刘德志”

  小结:搜索的文字需要匹配到集合中所有名字的子集。

全拼搜索:

  1. 搜索“li”,匹配到“刘德华”、“刘斌”、“刘德志”

  2. 搜索“liud”,匹配到“刘德华”、“刘德”

  3. 搜索“liudeh”,匹配到“刘德华”

  小结:搜索的文字转换成拼音后,需要匹配到集合中所有名字转成拼音后的子集

简拼搜索:

  1. 搜索“w”,匹配到“我是中国人”,“我爱我的祖国”

  2. 搜索“wszg”,匹配到“我是中国人”

  小结:搜索的文字取拼音首字母进行组合,需要匹配到组合字符串中前缀匹配的子集

解决方案

方案一:

  将 “like” 搜索的字段的 中、英简拼、英全拼 分别用索引的三个字段来进行存储并且 不进行分词,最简单直接,检索索引数据的时候进行通配符查询(like查询),从这三个字段中分别进行搜索,查询匹配的记录然后返回。

  优势:存储格式简单,倒排索引存储的数据量最少。

  缺点:like 索引数据的时候开销比较大 prefix 查询比 term 查询开销大得多

方案二:

  将 中、中简拼、中全拼 用一个字段衍生出三个字段(multi-field)来存储三种数据,并且分词器filter 采用 edge_ngram 类型对分词的数据进行分词处理存储到倒排索引中,当检索索引数据时,检索所有字段的数据。

  优势:格式紧凑,检索索引数据的时候采用 term 全匹配规则,也无需对入参进行分词,查询效率高。

  缺点:采用以空间换时间的策略,但是对索引来说可以接受。采用衍生字段来存储,增加了存储及检索的复杂度,对于三个字段搜索会将相关度相加,容易混淆查询相关度结果

方案三:

  将索引数据存储在一个不需分词的字段中(keyword), 生成倒排索引时进行三种类型倒排索引的生成,倒排索引生成的时候采用 edge_ngram 对倒排进一步拆分,以满足业务场景需求,检索时不对入参进行分词。

  优势:索引数据存储简单,检索索引数据的时只需对一个字段采用 term 全匹配查询规则,查询效率极高。

  缺点:采用以空间换时间的策略——比方案二要少,对索引数据来说可以接受。 

ES 针对这一业务场景解决方案还有很多种,先列出比较典型的这三种方案,选择方案三来进行处理。

准备工作

  • pinyin分词插件安装及参数解读
  • ElasticSearch edge_ngram 使用
  • ElasticSearch multi-field 使用
  • ElasticSearch 多种查询特性熟悉

代码

myself_settings.json:

{
"refresh_interval":"2s",
"number_of_replicas":1,
"number_of_shards":2,
"analysis":{
"filter":{
"autocomplete_filter":{
"type":"edge_ngram",
"min_gram":1,
"max_gram":15
},
"pinyin_first_letter_and_full_pinyin_filter" : {
"type" : "pinyin",
"keep_first_letter" : true,
"keep_full_pinyin" : false,
"keep_joined_full_pinyin": true,
"keep_none_chinese" : false,
"keep_original" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"trim_whitespace" : true,
"keep_none_chinese_in_first_letter" : true
},
"full_pinyin_filter" : {
"type" : "pinyin",
"keep_first_letter" : true,
"keep_full_pinyin" : false,
"keep_joined_full_pinyin": true,
"keep_none_chinese" : false,
"keep_original" : true,
"limit_first_letter_length" : 16,
"lowercase" : true,
"trim_whitespace" : true,
"keep_none_chinese_in_first_letter" : true
}
},
"analyzer":{
"full_prefix_analyzer":{
"type":"custom",
"char_filter": [
"html_strip"
],
"tokenizer":"keyword",
"filter":[
"lowercase",
"full_pinyin_filter",
"autocomplete_filter"
]
},
"chinese_analyzer":{
"type":"custom",
"char_filter": [
"html_strip"
],
"tokenizer":"keyword",
"filter":[
"lowercase",
"autocomplete_filter"
]
},
"pinyin_analyzer":{
"type":"custom",
"char_filter": [
"html_strip"
],
"tokenizer":"keyword",
"filter":[
"pinyin_first_letter_and_full_pinyin_filter",
"autocomplete_filter"
]
}
}
}
}

myself_mapping.json

{
"test_type": {
"properties": {
"full_name": {
"type": "text",
"analyzer": "full_prefix_analyzer"
},
"age": {
"type": "integer"
}
}
}
}

工程目录:

    

测试项目代码:

public class PrefixTest {

    @Test
public void testCreateIndex() throws Exception{
TransportClient client = ESConnect.getInstance().getTransportClient();
//定义索引
BaseIndex.createWithSetting(client,"baidu_index","esjson/baidu_settings.json");
//定义类型及字段详细设计
BaseIndex.createMapping(client,"baidu_index","baidu_type","esjson/baidu_mapping.json");
}
@Test
public void testBulkInsert() throws Exception{
TransportClient client = ESConnect.getInstance().getTransportClient();
List<Object> list = new ArrayList<>();
list.add(new BulkInsert(12l,"我们都有一个家名字叫中国",12));
list.add(new BulkInsert(13l,"兄弟姐妹都很多景色也不错 ",13));
list.add(new BulkInsert(14l,"家里盘着两条龙是长江与黄河",14));
list.add(new BulkInsert(15l,"还有珠穆朗玛峰儿是最高山坡",15));
list.add(new BulkInsert(16l,"我们都有一个家名字叫中国",16));
list.add(new BulkInsert(17l,"兄弟姐妹都很多景色也不错",17));
list.add(new BulkInsert(18l,"看那一条长城万里在云中穿梭",18));
boolean flag = BulkOperation.batchInsert(client,"baidu_index","baidu_type",list);
System.out.println(flag);
}
}

接下来查看下定义的分词器效果:

http://192.168.20.114:9200/baidu_index/_analyze?text=刘德华AT2016&analyzer=full_prefix_analyzer

得到的结果内容为:

{
"tokens": [
{
"token": "刘",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华a",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华at",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华at2",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华at20",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华at201",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "刘德华at2016",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "l",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "li",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liu",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liud",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liude",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liudeh",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liudehu",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "liudehua",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "l",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ld",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldh",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldha",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldhat",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldhat2",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldhat20",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldhat201",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
},
{
"token": "ldhat2016",
"start_offset": 0,
"end_offset": 9,
"type": "word",
"position": 0
}
]
}

看到以上结果,则表明大功告成了!

ElasticStack系列之十三 & 联想补全策略的更多相关文章

  1. 【Qt编程】基于Qt的词典开发系列<十四>自动补全功能

    最近写了一个查单词的类似有道词典的软件,里面就有一个自动补全功能(即当你输入一个字母时,就会出现几个候选项).这个自动补全功能十分常见,百度搜索关键词时就会出现.不过它们这些补全功能都是与你输入的进行 ...

  2. 9. VIM 系列 - YouCompleteMe 实现代码补全

    目录 环境准备 插件安装 环境准备 $ sudo apt install build-essential cmake python3-dev python-dev $ sudo apt install ...

  3. TensorFlow系列专题(十三): CNN最全原理剖析(续)

    目录: 前言 卷积层(余下部分) 卷积的基本结构 卷积层 什么是卷积 滑动步长和零填充 池化层 卷积神经网络的基本结构 总结 参考文献   一.前言 上一篇我们一直说到了CNN[1]卷积层的特性,今天 ...

  4. 联想功能 Jquery autocomplete.js输入框联想补全功能

    转载地址:https://www.cnblogs.com/jinzhiming/p/6768402.html

  5. Jquery autocomplete.js输入框联想补全功能

    Jquery autocomplete.js插件下载地址:http://files.cnblogs.com/files/jinzhiming/autocomplete.rar 有两种用法,一种是直接使 ...

  6. ES系列十三、Elasticsearch Suggester API(自动补全)

    1.概念 1.补全api主要分为四类 Term Suggester(纠错补全,输入错误的情况下补全正确的单词) Phrase Suggester(自动补全短语,输入一个单词补全整个短语) Comple ...

  7. [jetbrains系列] 外链第三方库+代码补全设置

    jetbrains系列的IDE真的是太好用了,有种相见恨晚的感觉. 在开发过程中第三方库是必不可少的,在开发的时候如果有一个可以补全的IDE可以节省查文档的时间. 举个例子:给pycharm配pysp ...

  8. IDEA 代码自动补全/自动联想 功能

    IDEA 的代码补全/自动联想功能,可以仅仅输入几个字母,自动补全一整段代码,非常舒服. 代码自动联想功能在 设置 -> Editor -> Live Templates 查看,很多都非常 ...

  9. ajax04_实现关键字联想和自动补全

    用ajax实现关键字联想和自动补全 遇到的小坑 回调函数相对window.onload的摆放位置 给回调函数addData传数据时,如何操作才能将数据传进去 代码实现 前端代码 <!DOCTYP ...

随机推荐

  1. Beta周王者荣耀交流协会第五次Scrum会议

    1. 立会照片 成员王超,高远博,冉华,王磊,王玉玲,任思佳,袁玥全部到齐. master:王磊 2. 时间跨度 2017年11月14日 19:00 — 19:50 ,总计50分钟. 3. 地点 一食 ...

  2. iOS软件"一天八杯水“app开发过程

    作为一个ios系统测试者和app外观设计者.我们首先要了解iOS系统的开发工具和资源.xcode和iOS sdk作为一个免费的开发环境值得我们去学习和了解.interface builder提供创建了 ...

  3. Scrum Meeting 3 -2014.11.5

    这几天小伙伴们都在努力,研究出不少改进方案并加以设计和实施了,分词算法的优化进度可观,而其他的任务在改进的过程中产生了些问题,对于之前代码的设计感到疑惑,我们找到了上届的学长们咨询,他们也给出了不少建 ...

  4. java 实验1

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计 班级:1352 姓名:杨光 学号:20135233 成绩:            指导教师:娄嘉鹏  实验 ...

  5. sql索引的填充因子多少最好,填充因子有什么用

    和索引重建最相关的是填充因子.当创建一个新索引,或重建一个存在的索引时,你可以指定一个填充因子,它是在索引创建时索引里的数据页被填充的数量.填充因子设置为100意味着每个索引页100%填满,50%意味 ...

  6. myeclipse 导入 import maven web project

    用google才收到了这个.. http://stackoverflow.com/questions/12197662/maven-java-web-project-not-recognised-wh ...

  7. Myeclipse2014 用Maven创建第一个web项目(1)---helloworld

    一.创建项目 1.Eclipse中用Maven创建项目 2.继续Next 3.选maven-archetype-webapp后,next 4.填写相应的信息,Packaged是默认创建一个包,不写也可 ...

  8. 关于mybatis的思考(1)——mybatis的使用实例

    架构分析 MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架. MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索.MyBatis 可以使用简 ...

  9. iOS开发面试题(中级)

    //想面试的童鞋们来看看自己会多少, 老鸟可以无视直接绕过...1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?与Ex ...

  10. Apache优化之多路处理模块理解

    前言: 当项目被多人访问时导致访问数度变慢,查了许多资料,了解到Apache的核心模块——MPM(多路处理访问模块).在此对MPM的一些知识点进行整理. MPM_WINNT模块 windows系统使用 ...