暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何基于ElasticSearch实现用户检索系统

不舍昼夜夫 2021-07-26
385

1. 序言

在大数据技术栈里,ElasticSearch常被作为NoSQL数据库用于OLAP查询场景。ElasticSearch底层基于Lucene索引实现,设计初衷是降低Lucene的使用门槛,并扩充其功能,用于全文检索领域。本文将介绍如何利用ElasticSearch提供的全文检索API实现用户检索系统。

2. 需求分析

2.1 用户数据

用户数据使用JSON格式,示例如下:

{
“id": 7788,
"nick_name": "天生妩媚",
"followers": 259
}

复制

id是用户唯一标识,nick_name代表用户昵称,followers代表粉丝量。

2.2 用户检索需求

用户检索需求非常简单,输入关键词,全文检索用户昵称,返回结果按相关性评分和用户粉丝量排序,相关性评分相当的情况下, 粉丝量越大的用户排名越靠前。

3. 系统实现

3.1 技术选型

ElasticSearch支持全文索引和检索,同时提供功能丰富的API方便自定义全文检索功能。由于原生ElasticSearch只支持分隔符的分词,不支持中文分词,需要选择中文分词插件。本文选用IK分词作为中文分词工具,IK可以很方便的与ElasticSearch进行集成。限于篇幅有限,本文不再介绍IK插件的安装。 感兴趣的同学可以查看官方文档:https://github.com/medcl/elasticsearch-analysis-ik

3.2 创建用户信息索引

在ElasticSearch中创建用户信息索引,索引的配置信息如下:

PUT user_info
{
"settings": {
"number_of_shards": 1,
"number_of_replicas" : 1,
"analysis" : {
"analyzer" : {
"character" : {
"filter" : [
"lowercase"
],
"tokenizer" : "character"
},
"pinyin_analyzer" : {
"tokenizer" : "pinyin_tokenizer"
}
},
"tokenizer" : {
"pinyin_tokenizer" : {
"keep_joined_full_pinyin" : "true",
"lowercase" : "true",
"keep_original" : "true",
"remove_duplicated_term" : "true",
"keep_separate_first_letter" : "false",
"type" : "pinyin",
"limit_first_letter_length" : "16",
"keep_full_pinyin" : "true"
},
"character" : {
"type" : "standard",
"max_token_length" : "1"
}
}
}
},
"mappings": {
"numeric_detection" : false,
"_source" : {
"enabled" : true
},
"properties": {
"id": {
"type": "long"
},
"nick_name" : {
"search_analyzer" : "ik_smart",
"similarity" : "BM25",
"analyzer" : "ik_max_word",
"type" : "text",
"fields" : {
"pinyin" : {
"search_analyzer" : "ik_smart",
"similarity" : "BM25",
"analyzer" : "pinyin_analyzer",
"type" : "text"
},
"chars" : {
"search_analyzer" : "ik_smart",
"similarity" : "BM25",
"analyzer" : "character",
"type" : "text"
}
}
},
"followers" : {
"type" : "long"
}
}
}
}

复制

索引配置说明:

  • 自定义分词器character,单个字符分词,解决检索关键词是单个字符的检索问题;

  • 自定义分词器pinyin_analyzer,将中文转化为拼音,实现拼音关键词检索;

  • nick_name多字段索引,用于单字符和拼音检索;

  • 指定nick_name字段全文检索相关性评分算法为BM25。

3.3 索引用户数据

向user_info索引写入三条用户数据。

POST user_info/_doc
{
"id": 7788,
"nick_name": "天生妩媚",
"followers": 8
}

POST user_info/_doc
{
"id": 7789,
"nick_name": "天生丽质",
"followers": 800
}

POST user_info/_doc
{
"id": 7790,
"nick_name": "小白",
"followers": 200
}

复制

3.4 用户数据检索

输入关键词,根据用户昵称全文检索用户数据。ElasticSearch检索请求参数如下:

POST user_info/_search
{
"query": {
"multi_match": {
"query": "天生",
"operator": "and",
"type": "most_fields",
"fields": ["nick_name", "nick_name.chars", "name.pinyin"]
}
}
}

复制

响应结果:

{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.47000363,
"hits" : [
{
"_index" : "user_info",
"_type" : "_doc",
"_id" : "BOVC-XQBGXOapfjvCQyw",
"_score" : 0.47000363,
"_source" : {
"id" : 7788,
"nick_name" : "天生妩媚",
"followers" : 8
}
},
{
"_index" : "user_info",
"_type" : "_doc",
"_id" : "BuVC-XQBGXOapfjvFAz-",
"_score" : 0.39019167,
"_source" : {
"id" : 7789,
"nick_name" : "天生丽质",
"followers" : 800
}
}
]
}
}

复制

从响应结果中可以看到用户“天生妩媚”的相关性评分是0.47,用户“天生丽质”的相关性评分是0.39。该相关性评分是通过BM25算法计算而来。

用户检索需求,需要检索结果的排序同时考虑粉丝量因素,粉丝量越大相关性评分越高。

ElasticSearch提供丰富的API,可以很方便的自定义相关性评分算法。要考虑粉丝量因素,将全文检索请求参数调整为如下形式即可实现。

POST user_info/_search
{
"query": {
"bool": {
"must": [
{
"function_score": {
"query": {
"multi_match": {
"query": "天生",
"operator": "and",
"type": "most_fields",
"fields": ["nick_name", "nick_name.chars", "name.pinyin"]
}
},
"field_value_factor": {
"field": "followers",
"factor": 1.0,
"modifier": "ln1p",
"missing": 1
},
"boost_mode": "multiply"
}
}
]
}
}
}

复制

上面请求参数的响应结果如下:

{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 2.6087673,
"hits" : [
{
"_index" : "user_info",
"_type" : "_doc",
"_id" : "BuVC-XQBGXOapfjvFAz-",
"_score" : 2.6087673,
"_source" : {
"id" : 7789,
"nick_name" : "天生丽质",
"followers" : 800
}
},
{
"_index" : "user_info",
"_type" : "_doc",
"_id" : "BOVC-XQBGXOapfjvCQyw",
"_score" : 1.0327035,
"_source" : {
"id" : 7788,
"nick_name" : "天生妩媚",
"followers" : 8
}
}
]
}
}

复制

此时全文检索的相关性评分算法是,相关性评分(BM25) * ln(1 + followers)。“天生丽质”的用户粉丝量远大于“天生妩媚”用户,相关性评分也就高了。

4. 总结与思考

用户检索系统实现的难点是优化检索结果,包括检索结果的准确性、相关性评分等。ElasticSearch提供丰富灵活的API,可以快速实现对全文检索结果的调整优化,极大的提高研发效率,是一款好用稳定的开源中间件。

文章转载自不舍昼夜夫,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论