Elasticsearch多索引混合搜索,搞定微信搜联系人需求
本文介绍了如何在Elasticsearch中实现微信联系人搜索功能的多数据源扩展与拼音检索优化。首先搭建个人微信(WeChat)联系人索引,通过自定义分词器和多字段配置支持全拼、简拼等拼音检索方式;然后以相同方式创建企业微信(WeCom)联系人索引;最后实现双索引混合搜索,满足用户一站式搜索需求。文章详细说明了索引创建、分析器配置及查询模板的实现过程,为类似搜索功能开发提供了参考方案。
手打不易,如果转摘,请注明出处!
本文链接:
https://zhangxiaofan.blog.csdn.net/article/details/159434022
文章目录
背景
因项目需要,APP的某个搜索框TAB,在原来搜索的基础上,需要添加新的搜索对象。
为方便理解,我们可以假设有如下需求:
现有微信 APP 通讯录搜索功能仅支持个人微信联系人检索;为满足用户一站式搜索需求,本次功能升级需扩展搜索范围,新增企业微信联系人检索能力。用户在通讯录搜索框中输入关键词时,需同时匹配个人微信与企业微信联系人,支持全拼、简拼、连写、分词等多种拼音检索方式,并按照业务规则排序、关键词高亮展示,提升搜索体验与效率。
简单的说,需求目标有2个:
-
数据源扩展:支持同时检索个人微信(WeChat)、企业微信(WeCom)两类本地联系人数据。
-
多维度拼音检索:覆盖中文全拼、简拼、连写拼音、原始中文分词四种检索方式,满足用户不同输入习惯
这个其实就是 搜索框合并多数据源搜索;假设个人微信(WeChat)和企业微信(WeCom)的联系人,都是存在手机或PC本地的Elasticsearch上。
步骤
本章节分三大模块逐步实现需求:先搭建个人微信联系人索引体系,再搭建企业微信联系人索引体系,最终实现双索引混合搜索,完整覆盖索引配置、分词器、查询模板、测试验证全流程。
WeChat联系人索引
索引创建
实现个人微信联系人的 Elasticsearch 搜索能力,核心是解决中文拼音多方式搜索、自定义排序。
创建索引
我们假设有age、sex、userName三个字段,希望用户在微信联系人中可以通过简拼、全拼、连写、分词等多种方式快速查找朋友。
PUT /wechat_contact
{
"mappings": {
"properties": {
"age": {
"type": "long"
},
"sex": {
"type": "integer"
},
"userName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"jianpin": {
"type": "text",
"analyzer": "pinyinJianPinAnalyzer"
},
"jianpin_all": {
"type": "text",
"analyzer": "pinyinJianPinAllAnalyzer"
},
"quanpin": {
"type": "text",
"analyzer": "pinyinQuanPinAnalyzer"
},
"quanpin_all": {
"type": "text",
"analyzer": "pinyinQuanPinAllAnalyzer"
}
}
}
}
},
"settings": {
"index": {
"number_of_shards": "8",
"number_of_replicas": "1"
},
"analysis": {
"filter": {
"pinyin_jianpin_filter": {
"lowercase": "true",
"keep_original": "false",
"keep_first_letter": "false",
"keep_separate_first_letter": "true",
"type": "pinyin",
"limit_first_letter_length": "50",
"keep_full_pinyin": "false"
},
"pinyin_quanpin_all_filter": {
"keep_joined_full_pinyin": "true",
"lowercase": "true",
"none_chinese_pinyin_tokenize": "false",
"keep_original": "false",
"remove_duplicated_term": "true",
"keep_separate_first_letter": "false",
"trim_whitespace": "true",
"type": "pinyin",
"limit_first_letter_length": "100",
"keep_none_chinese_in_joined_full_pinyin": "true",
"keep_first_letter": "false",
"keep_none_chinese": "true",
"keep_full_pinyin": "false"
},
"pinyin_quanpin_filter": {
"lowercase": "true",
"keep_original": "false",
"keep_first_letter": "false",
"keep_separate_first_letter": "false",
"type": "pinyin",
"keep_none_chinese": "true",
"limit_first_letter_length": "100",
"keep_full_pinyin": "true"
},
"pinyin_jianpin_all_filter": {
"keep_separate_first_letter": "false",
"none_chinese_pinyin_tokenize": "false",
"type": "pinyin",
"keep_none_chinese": "false",
"limit_first_letter_length": "100",
"keep_full_pinyin": "false"
}
},
"analyzer": {
"pinyinJianPinAllAnalyzer": {
"filter": [
"pinyin_jianpin_all_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "keyword"
},
"pinyinQuanPinAllAnalyzer": {
"filter": [
"pinyin_quanpin_all_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "keyword"
},
"pinyinQuanPinAnalyzer": {
"filter": [
"pinyin_quanpin_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "standard"
},
"pinyinJianPinAnalyzer": {
"filter": [
"pinyin_jianpin_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "standard"
}
},
"tokenizer": {
"ngram_tokenizer": {
"token_chars": [],
"min_gram": "1",
"type": "ngram",
"max_gram": "1"
}
}
}
}
}
索引解析
| 分析器 | tokenizer | filter | 作用 |
|---|---|---|---|
pinyinJianPinAnalyzer |
standard |
pinyin_jianpin_filter + lowercase |
将中文按字切分,每个字生成其拼音首字母(如“张” → z)。 |
pinyinJianPinAllAnalyzer |
keyword |
pinyin_jianpin_all_filter + lowercase |
将整个输入作为一个词元,转换为拼音首字母连写(如“张小凡” → zxf)。 |
pinyinQuanPinAnalyzer |
standard |
pinyin_quanpin_filter + lowercase |
将中文按字切分,每个字生成完整拼音(如“张” → zhang)。 |
pinyinQuanPinAllAnalyzer |
keyword |
pinyin_quanpin_all_filter + lowercase |
将整个输入作为一个词元,转换为完整拼音连写(如“张小凡” → zhangxiaofan)。 |
实际效果分词可以用下面语句测试:
POST /wechat_contact/_analyze
{
"text": "张小凡" ,
"analyzer":"pinyinJianPinAnalyzer"
}
POST /wechat_contact/_analyze
{
"text": "张小凡" ,
"analyzer":"pinyinJianPinAllAnalyzer"
}
POST /wechat_contact/_analyze
{
"text": "张小凡" ,
"analyzer":"pinyinQuanPinAnalyzer"
}
POST /wechat_contact/_analyze
{
"text": "张小凡" ,
"analyzer":"pinyinQuanPinAllAnalyzer"
}
创建查询模板
查询模板用于简化搜索语句、提升开发效率,我们先编写原生查询语句,再封装为可复用的模板,同时实现女性联系人优先展示的业务排序需求。
原查询语句
个人微信联系人的原生搜索语句
{
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{
"term": {
"sex":{
"value": 0, // 假设业务要求女性优先展示
"boost": 1000
}
}
},
{
"dis_max": {
"queries": [
{
"constant_score": {
"filter": {
"term": {
"userName.keyword": {
"value": "{$searchKey}"
}
}
},
"boost": 200
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName": "{$searchKey}"
}
},
"boost": 95
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.quanpin": "{$searchKey}"
}
},
"boost": 90
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.jianpin": "{$searchKey}"
}
},
"boost": 85
}
}
]
}
}
]
}
},
"highlight": {
"fields": {
"userName": {
"number_of_fragments": 0
},
"userName.jianpin": {
"number_of_fragments": 0
},
"userName.keyword": {
"number_of_fragments": 0
},
"userName.quanpin": {
"number_of_fragments": 0
},
"userName.quanpin_all": {
"number_of_fragments": 0
}
},
"post_tags": [
"</font>"
],
"pre_tags": [
"<font color='red'>"
]
},
"from": 1,
"size": 10
}
创建模板
将原生查询语句封装为 ES 脚本模板,通过动态参数searchKey实现灵活搜索,简化后续测试与调用成本
POST _scripts/wechat_contact_search_template
{
"script": {
"params": {
"searchKey": ""
},
"lang": "mustache",
"source": {
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{
"term": {
"sex":{
"value": 0, // 假设业务要求女性优先展示
"boost": 1000
}
}
},
{
"dis_max": {
"queries": [
{
"constant_score": {
"filter": {
"term": {
"userName.keyword": {
"value": "{{searchKey}}"
}
}
},
"boost": 100
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.quanpin_all": "{{searchKey}}"
}
},
"boost": 90
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.jianpin_all": "{{searchKey}}"
}
},
"boost": 80
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName": "{{searchKey}}"
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.quanpin": "{{searchKey}}"
}
},
"boost": 15
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.jianpin": "{{searchKey}}"
}
},
"boost": 10
}
}
]
}
}
]
}
},
"highlight": {
"fields": {
"userName": {
"number_of_fragments": 0
},
"userName.jianpin": {
"number_of_fragments": 0
},
"userName.keyword": {
"number_of_fragments": 0
},
"userName.quanpin": {
"number_of_fragments": 0
},
"userName.quanpin_all": {
"number_of_fragments": 0
}
},
"post_tags": [
"</font>"
],
"pre_tags": [
"<font color='red'>"
]
},
"from": 0,
"size": 10
}
}
}
模板解析
{
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{ "term": { "sex": { "value": 0, "boost": 1000 } } }, // 女性优先
{ "dis_max": { "queries": [ ... ] } } // 拼音匹配
]
}
},
"highlight": { ... },
"from": 0,
"size": 10
}
为了方便测试,这里女性优先级最高:
- 对
sex字段执行term查询,匹配值为0(假设女性)的文档。 - 赋予超高
boost = 1000,使得女性文档在得分上获得巨大优势,从而排在搜索结果前列。
内部包含六个 constant_score 查询,每个查询使用不同的字段进行精确匹配(term 或 match_phrase),并赋予不同的固定得分(boost)。dis_max 会从所有匹配的子句中选取 最高得分 作为该子句的总得分。
| 子句 | 查询类型 | 字段 | 匹配逻辑 | 得分 (boost) |
|---|---|---|---|---|
| 1 | term |
userName.keyword |
精确匹配整个字符串 | 100 |
| 2 | match_phrase |
userName.quanpin_all |
短语匹配连写全拼 | 90 |
| 3 | match_phrase |
userName.jianpin_all |
短语匹配连写简拼 | 80 |
| 4 | match_phrase |
userName(text) |
短语匹配原始中文分词 | 20 |
| 5 | match_phrase |
userName.quanpin |
短语匹配分词全拼 | 15 |
| 6 | match_phrase |
userName.jianpin |
短语匹配分词简拼 | 10 |
注意:match_phrase 要求查询词经过该字段的分析器处理后生成的词项序列,与文档中该字段的词项序列完全一致(顺序相同)。term 则要求完全相等。
整体得分计算如下:
bool 查询中多个 should 子句的得分 相加。因此:
总分 = score(sex term) + score(dis_max)
score(sex term):由term查询本身的相关性得分(基于词频、逆文档频率等)乘以boost=1000得到。score(dis_max):dis_max内所有匹配子句的最高boost(因为这些子句都是constant_score,匹配即得固定分)。
查询测试
插入数据
POST /wechat_contact/_bulk
{"index":{"_id":1}}
{"userName":"张小凡","age":18,"sex":1}
{"index":{"_id":2}}
{"userName":"李张娜","age":25,"sex":0}
{"index":{"_id":3}}
{"userName":"吴张刚","age":32,"sex":1}
{"index":{"_id":4}}
{"userName":"刘洋","age":28,"sex":1}
{"index":{"_id":5}}
查询测试
POST /wechat_contact/_search/template
{
"id": "wechat_contact_search_template",
"params": {
"searchKey": "张"
}
}
结果
结果按照预期排序:女性联系人(sex=0)排在最前面,其他联系人按照匹配的精度排序。highlight 功能清晰地标出了匹配的部分
{
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1020.0,
"hits": [
{
"_index": "wechat_contact",
"_type": "_doc",
"_id": "2",
"_score": 1020.0,
"_source": {
"userName": "李张娜",
"age": 25,
"sex": 0
}
},
{
"_index": "wechat_contact",
"_type": "_doc",
"_id": "1",
"_score": 20.0,
"_source": {
"userName": "张小凡",
"age": 18,
"sex": 1
}
},
{
"_index": "wechat_contact",
"_type": "_doc",
"_id": "3",
"_score": 20.0,
"_source": {
"userName": "吴张刚",
"age": 32,
"sex": 1
}
}
]
}
}
WeCom联系人索引
复刻个人微信联系人的配置逻辑,实现企业微信联系人的搜索能力,仅修改字段名区分数据源,保证双数据源搜索逻辑统一。
创建索引
创建企业微信联系人索引wecom_contact,拼音分词配置与个人微信完全一致,仅修改字段名(age2/userName2),保持搜索能力对齐。
PUT /wecom_contact
{
"mappings": {
"properties": {
"age2": {
"type": "long"
},
"sex": {
"type": "integer"
},
"userName2": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"jianpin": {
"type": "text",
"analyzer": "pinyinJianPinAnalyzer"
},
"jianpin_all": {
"type": "text",
"analyzer": "pinyinJianPinAllAnalyzer"
},
"quanpin": {
"type": "text",
"analyzer": "pinyinQuanPinAnalyzer"
},
"quanpin_all": {
"type": "text",
"analyzer": "pinyinQuanPinAllAnalyzer"
}
}
}
}
},
"settings": {
"index": {
"number_of_shards": "8",
"number_of_replicas": "1"
},
"analysis": {
"filter": {
"pinyin_jianpin_filter": {
"lowercase": "true",
"keep_original": "false",
"keep_first_letter": "false",
"keep_separate_first_letter": "true",
"type": "pinyin",
"limit_first_letter_length": "50",
"keep_full_pinyin": "false"
},
"pinyin_quanpin_all_filter": {
"keep_joined_full_pinyin": "true",
"lowercase": "true",
"none_chinese_pinyin_tokenize": "false",
"keep_original": "false",
"remove_duplicated_term": "true",
"keep_separate_first_letter": "false",
"trim_whitespace": "true",
"type": "pinyin",
"limit_first_letter_length": "100",
"keep_none_chinese_in_joined_full_pinyin": "true",
"keep_first_letter": "false",
"keep_none_chinese": "true",
"keep_full_pinyin": "false"
},
"pinyin_quanpin_filter": {
"lowercase": "true",
"keep_original": "false",
"keep_first_letter": "false",
"keep_separate_first_letter": "false",
"type": "pinyin",
"keep_none_chinese": "true",
"limit_first_letter_length": "100",
"keep_full_pinyin": "true"
},
"pinyin_jianpin_all_filter": {
"keep_separate_first_letter": "false",
"none_chinese_pinyin_tokenize": "false",
"type": "pinyin",
"keep_none_chinese": "false",
"limit_first_letter_length": "100",
"keep_full_pinyin": "false"
}
},
"analyzer": {
"pinyinJianPinAllAnalyzer": {
"filter": [
"pinyin_jianpin_all_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "keyword"
},
"pinyinQuanPinAllAnalyzer": {
"filter": [
"pinyin_quanpin_all_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "keyword"
},
"pinyinQuanPinAnalyzer": {
"filter": [
"pinyin_quanpin_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "standard"
},
"pinyinJianPinAnalyzer": {
"filter": [
"pinyin_jianpin_filter",
"lowercase"
],
"type": "custom",
"tokenizer": "standard"
}
},
"tokenizer": {
"ngram_tokenizer": {
"token_chars": [],
"min_gram": "1",
"type": "ngram",
"max_gram": "1"
}
}
}
}
}
插入数据
POST /wecom_contact/_bulk
{"index":{"_id":1}}
{"userName2":"张小凡","age2":18,"sex":1}
{"index":{"_id":2}}
{"userName2":"李张娜","age2":25,"sex":0}
{"index":{"_id":3}}
{"userName2":"吴张刚","age2":32,"sex":1}
{"index":{"_id":4}}
{"userName2":"刘洋","age2":28,"sex":1}
{"index":{"_id":5}}
创建模板
创建企业微信联系人专用查询模板,仅修改匹配字段为userName2,其余逻辑(权重、高亮、排序)与个人微信完全一致。
POST _scripts/wecom_contact_search_template
{
"script": {
"params": {
"searchKey": ""
},
"lang": "mustache",
"source": {
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{
"term": {
"sex":{
"value": 0,
"boost": 1000
}
}
},
{
"dis_max": {
"queries": [
{
"constant_score": {
"filter": {
"term": {
"userName2.keyword": {
"value": "{{searchKey}}"
}
}
},
"boost": 100
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.quanpin_all": "{{searchKey}}"
}
},
"boost": 90
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.jianpin_all": "{{searchKey}}"
}
},
"boost": 80
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2": "{{searchKey}}"
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.quanpin": "{{searchKey}}"
}
},
"boost": 15
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.jianpin": "{{searchKey}}"
}
},
"boost": 10
}
}
]
}
}
]
}
},
"highlight": {
"fields": {
"userName2": {
"number_of_fragments": 0
},
"userName2.jianpin": {
"number_of_fragments": 0
},
"userName2.keyword": {
"number_of_fragments": 0
},
"userName2.quanpin": {
"number_of_fragments": 0
},
"userName2.quanpin_all": {
"number_of_fragments": 0
}
},
"post_tags": [
"</font>"
],
"pre_tags": [
"<font color='red'>"
]
},
"from": 0,
"size": 10
}
}
}
查询测试
调用企业微信查询模板,验证单数据源搜索功能正常。
POST /wecom_contact/_search/template
{
"id": "wecom_contact_search_template",
"params": {
"searchKey": "张"
}
}
结果跟WeChat排序和得分类似,接下来我们看看,如何把2个不同的"数据源"(索引),放在一起搜索,同时按一定的得分规则排序。
多索引混合搜索(WeChat+WeCom)
实现同时搜索个人微信 + 企业微信两个索引,合并搜索结果,保持统一的排序、高亮、权重规则,完成业务需求。
原查询语句(多索引)
为了实现多索引混合搜索,我们将两个索引的匹配子句合并到同一个 dis_max 查询中。需要注意的是,由于两个索引的字段名不同(userName vs userName2),我们需要在查询中同时包含这两套字段的匹配条件。
{
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{
"term": {
"sex": "0"
},
"boost": 140
},
{
"dis_max": {
"queries": [
// ---------- 索引1的字段 ----------
{
"constant_score": {
"filter": {
"term": { "userName.keyword": { "value": "{{searchKey}}" } }
},
"boost": 200
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName": "{{searchKey}}" }
},
"boost": 95
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName.quanpin": "{{searchKey}}" }
},
"boost": 90
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName.jianpin": "{{searchKey}}" }
},
"boost": 85
}
},
// ---------- 索引2的字段 ----------
{
"constant_score": {
"filter": {
"term": { "userName2.keyword": { "value": "{{searchKey}}" } }
},
"boost": 200
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName2": "{{searchKey}}" }
},
"boost": 95
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName2.quanpin": "{{searchKey}}" }
},
"boost": 90
}
},
{
"constant_score": {
"filter": {
"match_phrase": { "userName2.quanpin_all": "{{searchKey}}" }
},
"boost": 90
}
}
]
}
}
]
}
},
"highlight": {
"fields": {
"userName": { "number_of_fragments": 0 },
"userName.jianpin": { "number_of_fragments": 0 },
"userName.keyword": { "number_of_fragments": 0 },
"userName.quanpin": { "number_of_fragments": 0 },
"userName.quanpin_all": { "number_of_fragments": 0 },
"userName2": { "number_of_fragments": 0 },
"userName2.keyword": { "number_of_fragments": 0 },
"userName2.quanpin": { "number_of_fragments": 0 },
"userName2.quanpin_all": { "number_of_fragments": 0 }
},
"post_tags": ["</font>"],
"pre_tags": ["<font color='red'>"]
},
"from": 0,
"size": 10
}
创建查询模板(多索引)
封装双索引混合搜索模板,整合个人微信userName和企业微信userName2所有匹配规则,支持动态关键词搜索。
POST _scripts/mixed_contact_search_template
{
"script": {
"params": {
"searchKey": ""
},
"lang": "mustache",
"source": {
"query": {
"bool": {
"minimum_should_match": 1,
"filter": [],
"should": [
{
"term": {
"sex":{
"value": 0,
"boost": 1000
}
}
},
{
"dis_max": {
"queries": [
{
"constant_score": {
"filter": {
"term": {
"userName.keyword": {
"value": "{{searchKey}}"
}
}
},
"boost": 200
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName": "{{searchKey}}"
}
},
"boost": 100
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.quanpin": "{{searchKey}}"
}
},
"boost": 50
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName.jianpin": "{{searchKey}}"
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"term": {
"userName2.keyword": {
"value": "{{searchKey}}"
}
}
},
"boost": 200
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2": "{{searchKey}}"
}
},
"boost": 100
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.quanpin": "{{searchKey}}"
}
},
"boost": 50
}
},
{
"constant_score": {
"filter": {
"match_phrase": {
"userName2.jianpin": "{{searchKey}}"
}
},
"boost": 20
}
}
]
}
}
]
}
},
"highlight": {
"fields": {
"userName": {
"number_of_fragments": 0
},
"userName.jianpin": {
"number_of_fragments": 0
},
"userName.keyword": {
"number_of_fragments": 0
},
"userName.quanpin": {
"number_of_fragments": 0
},
"userName.quanpin_all": {
"number_of_fragments": 0
},
"userName2": {
"number_of_fragments": 0
},
"userName2.keyword": {
"number_of_fragments": 0
},
"userName2.quanpin": {
"number_of_fragments": 0
},
"userName2.quanpin_all": {
"number_of_fragments": 0
}
},
"post_tags": [
"</font>"
],
"pre_tags": [
"<font color='red'>"
]
},
"from": 0,
"size": 10
}
}
}
查询测试(多索引)
ES 支持多索引逗号分隔查询,调用混合搜索模板,同时查询wechat_contact和wecom_contact两个索引
POST /wechat_contact,wecom_contact/_search/template
{
"id": "mixed_contact_search_template",
"params": {
"searchKey": "zhang"
}
}
查询结果
从结果中可以看到,两个索引的数据被无缝地合并在一起,且高亮功能在两个索引的字段上都能正常工作。证明了多索引混合搜索的可行性和实用性。最终我们完成了多索引混合搜索!
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 16,
"successful" : 16,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 6,
"relation" : "eq"
},
"max_score" : 1050.0,
"hits" : [
{
"_index" : "wechat_contact",
"_type" : "_doc",
"_id" : "2",
"_score" : 1050.0,
"_source" : {
"userName" : "李张娜",
"age" : 25,
"sex" : 0
},
"highlight" : {
"userName.quanpin" : [
"李<font color='red'>张</font>娜"
]
}
},
{
"_index" : "wecom_contact",
"_type" : "_doc",
"_id" : "2",
"_score" : 1050.0,
"_source" : {
"userName2" : "李张娜",
"age2" : 25,
"sex" : 0
},
"highlight" : {
"userName2.quanpin" : [
"李<font color='red'>张</font>娜"
]
}
},
{
"_index" : "wechat_contact",
"_type" : "_doc",
"_id" : "1",
"_score" : 50.0,
"_source" : {
"userName" : "张小凡",
"age" : 18,
"sex" : 1
},
"highlight" : {
"userName.quanpin" : [
"<font color='red'>张</font>小凡"
]
}
},
{
"_index" : "wecom_contact",
"_type" : "_doc",
"_id" : "1",
"_score" : 50.0,
"_source" : {
"userName2" : "张小凡",
"age2" : 18,
"sex" : 1
},
"highlight" : {
"userName2.quanpin" : [
"<font color='red'>张</font>小凡"
]
}
},
{
"_index" : "wechat_contact",
"_type" : "_doc",
"_id" : "3",
"_score" : 50.0,
"_source" : {
"userName" : "吴张刚",
"age" : 32,
"sex" : 1
},
"highlight" : {
"userName.quanpin" : [
"吴<font color='red'>张</font>刚"
]
}
},
{
"_index" : "wecom_contact",
"_type" : "_doc",
"_id" : "3",
"_score" : 50.0,
"_source" : {
"userName2" : "吴张刚",
"age2" : 32,
"sex" : 1
},
"highlight" : {
"userName2.quanpin" : [
"吴<font color='red'>张</font>刚"
]
}
}
]
}
}
总结
通过本文的实践,我们成功地将两个独立索引的搜索功能整合为一个统一的混合搜索。整个过程涵盖了索引设计、分析器配置、模板创建和混合查询等多个环节。这种方案具有以下优势:
- 数据隔离:不同数据源依然存储在不同的索引中,便于管理和维护。
- 逻辑统一:搜索逻辑在查询层统一,无需改动原有数据。
- 扩展性强:未来新增数据源时,只需在现有模板中添加对应的字段匹配条件即可。
希望本文的实践能够为有类似需求的开发者提供一些参考和启发!!!
更多推荐
所有评论(0)