本篇我们介绍一下部分搜索的几种玩法,我们经常使用的浏览器搜索框,输入时会弹出下拉提示,也是基于局部搜索原理实现的。
我们在前面了解的搜索,词条是最小的匹配单位,也是倒排索引中存在的词,现在我们来聊聊部分匹配的话题,只匹配一个词条中的一部分内容,相当于mysql的"where content like ‘%love%’",在数据库里一眼就能发现这种查询是不走索引的,效率非常低。
Elasticsearch对这种搜索有特殊的拆分处理,支持多种部分搜索格式,这次重点在于not_analyzed精确值字段的前缀匹配。
我们常见的可能有前缀搜需求的有邮编、产品序列号、快递单号、证件号的搜索,这些值的内容本身包含一定的逻辑分类含义,如某个前缀表示地区、年份等信息,我们以邮编为例子:
# 只创建一个postcode字段,类型为keyword
PUT /demo_index
{
"mappings": {
"address": {
"properties": {
"postcode": {
"type": "keyword"
}
}
}
}
}
# 导入一些示例的邮编
POST /demo_index/address/_bulk
{
"index": {
"_id": 1 }}
{
"postcode" : "510000"}
{
"index": {
"_id": 2 }}
{
"postcode" : "514000"}
{
"index": {
"_id": 3 }}
{
"postcode" : "527100"}
{
"index": {
"_id": 4 }}
{
"postcode" : "511500"}
{
"index": {
"_id": 5 }}
{
"postcode" : "511100"}
前缀搜索示例:
GET /demo_index/address/_search
{
"query": {
"prefix": {
"postcode": {
"value": "511"
}
}
}
}
搜索结果可以看到两条,符合预期:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "demo_index",
"_type": "address",
"_id": "5",
"_score": 1,
"_source": {
"postcode": "511100"
}
},
{
"_index": "demo_index",
"_type": "address",
"_id": "4",
"_score": 1,
"_source": {
"postcode": "511500"
}
}
]
}
}
prefix query不计算relevance score,_score固定为1,与prefix filter唯一的区别就是,filter会cache bitset。
我们分析一下示例的搜索过程:
postcode | doc ids |
---|---|
510000 | 1 |
514000 | 2 |
527100 | 3 |
511500 | 4 |
511100 | 5 |