基于ElasticSearch分布式搜索引擎的信息检索方法研究

2023-12-28 08:35董元和李恩泽薛贤红
关键词:词条字段分词

董元和,贾 炎,朱 勇,李恩泽,薛贤红

(1.湖北师范大学 计算机与信息工程学院,湖北 黄石 435002;2.黄石市第十四中学,湖北 黄石 435002)

0 引言

随着互联网的快速发展,每天产生大量数据,但其中有很多是脏数据。传统的搜索方式无法应对海量信息的并发查询和筛选,也无法满足多关键词组合的短文本搜索需求,搜索结果的相关性也有一定偏差。因此,本文提出使用基于ElasticSearch分布式搜索引擎[1]的方法,提供更具体、有效和深入的垂直搜索服务[2],研究重点是基于分布式搜索引擎,结合中文分词技术和搜索相关性算分排序技术,设计并实现基于ElasticSearch分布式搜索引擎的信息检索系统。

1 系统关键技术

1.1 分词器

在本文所阐述的系统中,对用户输入的搜索内容进行分词处理是一个重要步骤,本系统采用的是ik分词器[3]。ElasticSearch内置了分词器,如标准分词器、简单分词器、空白词器等。但这些分词器对中文的支持并不友好,不能按中文的语言习惯进行分词。而ik分词器就是一个标准的中文分词器,它可以根据定义的字典对域进行分词,并且支持用户配置自己的字典。除此之外,ik分词器还具有2种分词算法:ik_smart(最粗粒度的拆分)和ik_max_word(最细粒度的拆分),ik_max_word比ik_smart划分的词条要更多。

1.2 倒排索引

倒排索引[4]的概念是基于关系型数据库的正向索引而言的。正向索引需要逐行扫描也就是全表扫描,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。因此,针对这类用正向索引会导致一些性能问题的业务可以考虑采取倒排索引的方式。创建倒排索引是对正向索引的一种特殊处理,步骤如下:

1) 将每一个文档(用来搜索的数据,其中的每一条数据就是一个文档)。的数据利用算法分词(通常会借助分词器),得到一个个词条(对文档数据或用户搜索数据,利用下文提到的分词器进行分词,得到的具备含义的词语就是词条);

2) 创建表,每行数据包括词条、词条所在文档id、位置等信息;

3) 因为词条的唯一性,可以给词条创建索引(就是文档的集合,类似数据库的表),例如hash表结构索引。

其整体流程如图1,以搜索“如家酒店”为例,用户输入条件“如家酒店”进行搜索;对用户输入内容分词,得到词条:“如家”“酒店”;拿着词条在倒排索引表2中查找,可以得到包含词条的文档id:1、2、3;拿着文档id到正向索引表1中查找具体的记录。

表1 正向索引idname1如家民宿2假日酒店3如家酒店4皇冠假日5清沐表2 倒排索引词条文档id如家1,3酒店2,3清沐5皇冠4假日2,4

图1 倒排索引流程图

虽然要先查询倒排索引,再查询正向索引,但是无论是词条、还是文档id都建立了索引,查询速度非常快,无须全表扫描。另外,ElasticSearch不仅提供了内置的分词器,也可以进行自定义分词器,并通过不同分词器的组合以及相关属性设置,去创建符合研究数据的分词器,极大地优化建立索引的速度。

1.3 相关性算分

相关性描述的是一个文档和查询语句匹配的程度。ElasticSearch会对每个匹配查询条件的结果进行算分(_score),_score的评分越高,相关度就越高。在ElasticSearch中,早期使用的打分算法是TF-IDF[5]算法,公式如下:

(1)

由此,可以得到结论:词条出现频率越高,相关性也越高。在后来的5.1版本升级中,ElasticSearch将算法改进为BM25[6]算法,公式如下:

(2)

这里tftq表示单词t在query中的词频,Lave是所有文档的平均长度,Ld是文档d的长度,k3是一个可调正参数,来矫正query中的词频范围。经过试验,上面三个可调参数,k1和k3可取1.2与2之间的数,b取0.75.显然,词条频率仍然对相关性占主导作用,但受到其他参数制约,使得结果更加准确。

2 具体实现

2.1 系统架构

本系统以Elasticsearch作为全文搜索引擎,客户端访问后端搜索模块时可以直接调用搜索服务,也可以通过调用ElasticSearch搜素引擎间接调用搜索服务,并将数据同步到数据库中。系统架构图如图2所示。

图2 系统架构图

2.2 环境搭建

首先需要安装ElasticSearch并且部署单点ElasticSearch服务;其次本系统还需要部署Kibana容器,因此需要让ElasticSearch和Kibana容器互联,所以先利用docker容器创建一个es-net网络;然后采用ElasticSearch的7.12.1版本的镜像,运行docker加载命令导入数据。同理还有Kibana的tar包也需要这样做。最后运行docker run命令,部署单点ElasticSearch和Kibana.接下来需要离线安装ik插件,安装插件需要知道ElasticSearch的plugins目录位置,因为系统用了数据卷挂载,所以需要查看ElasticSearch的数据卷目录,根据Mountpoint字段的属性值即可知道plugins目录被挂载到了哪个目录,接着将插件拷贝到该目录中,之后重新启动ElasticSearch服务即可。

2.3 创建索引库

倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,因此索引库一旦创建,无法修改mapping,这就需要根据关系表字段重新定义自己的索引库。同时,创建索引库最关键的是mapping映射,而mapping映射要考虑的信息包括type(字段数据类型)、index(是否创建索引,默认为true)、analyzer(使用哪种分词器)、properties(该字段的子字段),针对此种情况可以考虑利用代码创建索引库,方便后期修改属性时删除索引库并重新创建索引库,核心代码如下:

void testCreateIndex() throws IOException {

// 1.准备Request

CreateIndexRequest request = new CreateIndexRequest("hotel");

// 2.准备请求参数MAPPING_TEMPLATE是自定义的索引库结构

request.source(MAPPING_TEMPLATE, XContentType.JSON);

// 3.发送请求

client.indices().create(request, RequestOptions.DEFAULT);

}

2.4 基础搜索功能实现

此小节主要是完成信息的基本查询,包括全文检索查询,精确查询,搜索查询等。全文检索查询首先要对用户搜索的内容做分词,得到词条;根据词条去倒排索引库中匹配,得到文档id;根据文档id找到记录,返回给用户,核心代码如下:

void testMatch() throws IOException {

// 1.准备request

SearchRequest request = new SearchRequest("hotel");

// 2.准备请求参数

request.source().query(QueryBuilders.multiMatchQuery("外滩如家", "name", "brand", "city"));

// 3.发送请求,得到响应

SearchResponse response = client.search(request, RequestOptions.DEFAULT);

// 4.结果解析

handleResponse(response);

}

上述代码中,multiMatchQuery是实现多字段查询,即任意一个字段符合条件就算符合查询条件,这种查询方式在正向索引库中实现起来要麻烦很多,性能也不够好。在ElasticSearch中还可以借助组合字段将多字段的值利用copy_to合并,提供给用户搜索,这样比上面代码中多个字段分开查询效率还要更高。而对于精确查询就简单了很多,与上面的查询相比,差异仅仅在查询条件,需要查询参数值与索引库值完全匹配,就跟关系型数据库的字段查询相似,只是数据足够大时,ElasticSearch查询效率要更高,代码如下:

void testBool() throws IOException {

……

request.source().query(

QueryBuilders.boolQuery()

.must(QueryBuilders.termQuery("city", "杭州"))

.filter(QueryBuilders.rangeQuery("price").lte(250))

);

……

}

2.5 地理搜索功能实现

ElasticSearchES中支持两种地理坐标数据类型,geo_point(由纬度(latitude)和经度(longitude)确定的一个点)和geo_shape(有多个geo_point组成的复杂几何图形)。首先基于这个location坐标,然后按照距离对信息排序,核心代码如下:

String location = params.getLocation();

if (StringUtils.isNotBlank(location)) {

request.source().sort(SortBuilders

.geoDistanceSort("location", new GeoPoint(location))

.order(SortOrder.ASC)

.unit(DistanceUnit.KILOMETERS)

);

}

2.6 算分排序功能实现

对于商业性质很强的业务场景,搜索结果优先顺序是十分重要的,关系到运营发展的重要决策和盈利能力。那么就需要借助算分算法得出相对比较公平的分数并进行排序并展现给用户,ElastiSearch利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列。

但是在B2B,B2C,C2C这种商业模式下,除了流量定向分发,还需要人为地控制相关性分数,提高搜索优先级,优先展示在用户列表中,这需要借助ElastiSearch的算分函数function_score查询,它可以影响算分,算分高了,自然排名也就高了。而function_score包含3个要素:过滤条件(哪些文档要加分)、算分函数(如何计算function_score)、加权方式(function_score与query_score如何运算)。想让指定的信息排名靠前,那么可以给这些信息添加一个标记,这样在过滤条件中就可以根据这个标记来判断,是否要提高算分。比如,给查询信息添加一个Boolean类型字段isAD,这样function_score包含3个要素就很好确定了:过滤条件:判断isAD是否为true,如果是就添加分数权值;算分函数:可以用最简单暴力的weight来实现固定加权值;加权方式:可以用默认的相乘提高算分,代码如下:

FunctionScoreQueryBuilderfunctionScoreQuery=QueryBuilders.functionScoreQuer(

boolQuery,

new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{

new FunctionScoreQueryBuilder.FilterFunctionBuilder(

QueryBuilders.termQuery("isAD", true),

ScoreFunctionBuilders.weightFactorFunction(10)

)

}

);

如图3,在查询之前设置标记字段isAD为true,这样会增加该条数据的权重,分数会被提高,这样查询结果中排序靠前的记录id值跟事先设置的文档id相同,这个结果也说明ElastiSearch是可以很方便地实现竞争排名。

图3 排名实现结果

3 结语

基于ElasticSearch分布式搜索引擎的信息检索系统,不仅可以实现对信息进行全文检索查询、精确查询、地理坐标查询以及算分排序等重要功能,而且搜索性能也会有大幅度提升,部署也简单方便,但仍有不足之处需要完善更新,比如未实现数据聚合实时搜索效果;未实现自动补全用户在搜索框输入字符时提示出与该字符有关的搜索项等功能。对此,后续可以考虑对用户常用搜索词条进行缓存处理。

猜你喜欢
词条字段分词
图书馆中文图书编目外包数据质量控制分析
分词在英语教学中的妙用
结巴分词在词云中的应用
结巴分词在词云中的应用
2016年4月中国直销网络热门词条榜
2016年3月中国直销网络热门词条榜
2016年9月中国直销网络热门词条榜
大数据相关词条
CNMARC304字段和314字段责任附注方式解析
无正题名文献著录方法评述