模拟实战京东搜索效果(二)

京东、淘宝无疑是中国电商界的传奇,虽然一个主打物流和质量、一个主打品类和价格,但它们都有一个共同的特点,那就是核心流量都来自用户搜索,用户都是通过搜索引擎选购心仪商品并下单购买的;一个好的搜索引擎不单单要关注点击与购买转化率,还要在产品体验上满足用户的要求 ,如缩短用户的查找路径,降低用户在购买商品时的决策时间。

Query下拉推荐是指搜索引擎系统根据用户当前的输入,自动提供一个Query候选列表供用户选择,Query下拉提示(Query suggestion)在搜索引擎和广告竞价平台中已经是标配的产品。Query suggestion可以帮助用户明确搜索意图,减少用户的输入并节约搜索时间,对提高搜索体验有重要作用。各个搜索系统的下拉推荐的处理流程基本相同,下拉推荐不同主要体现在后台查询机制的不同,下面介绍几种京东搜索框效果:

搜索框提示效果

这里面大致包含如下几个功能点:

  • 中文文本提示 ,如输入 小米 ,会提示 小米手机
  • 拼音输入,如输入 xiaomi ,提示 小米手机
  • 中文拼音混合,如输入 小mi,提示 小米手机
  • 中文简拼混合,如输入 xm手机,会提示 小米手机;输入 小米sj 同样会提示 小米手机
  • 关联商品数量,联想提示词右边会关联该联想词可能命中的商品数量
  • 提示纠错,京东会根据历史搜索词条对用户部分搜索关键词进行纠错 如输入 平果 ,会提示 苹果
image.png
image.png

搜索词推荐

  • 热词推荐
  • 相近词推荐


    image.png

意图识别

当用户输入关键词比较长,或商品库中没有匹配的商品时,京东会对用户输入语句进行意图识别,分析用户最想要的是什么,找到核心关键词并进行相关推荐。
如用户输入 五彩斑斓的苹果球鞋 时,京东会先进行一次精确搜索,当所有词都匹配上时才会返回结果,如果没有结果返回,京东服务端会进行查询改写,将用户输入关键词匹配度降低50%后去商品库再进行一次模糊搜索,如果还找不到匹配的商品时,京东会进行意图识别,对识别的关键词进行推荐;“五彩斑斓的苹果球鞋” 分词后被拆分成 五彩斑斓、苹果、球鞋,显然没有匹配的商品,模糊50%需要同时满足其中任意两个词同时出现,显然也没有对应的商品(这里大家可以试着增加 耐克 或删除 苹果 看下效果),在上述环节都无结果时 最后从用户输入关键词中识别出球鞋,并进行相关商品推荐。


image.png

实现

鉴于第一版易企秀商城大搜效果一直被大家吐槽,今天我们就仿造京东来一波优化,通过ES实现 输入框联想词提示 及 对用户输入词进行意图分析。

基本流程

输入框联想词提示

这里有两种实现方案,一种是通过ES官方自带的算法支持,另外一种我们通过edge n-gram实现。

edge n-gram

什么是edge n-gram ? 假设有一个词hello,普通建索引时,就是把这个词hello放入倒排索引
用户输入h、he时会找不到索引(倒排索引中只有hello),因此匹配失败
而对于输入即搜索这种应用场景,可以使用一种特殊的n-gram,称为边界n-grams (edge n-grams)
所谓的edge n-gram,就是指它会固定从一边开始,进行窗口滑动,每次滑动长度为1,最终的结果取决于 n 的选择长度
以单词hello为例,它的edge n-gram的结果如下:

h
he
hel
hell
hello

因此可以发现到,在使用edge n-gram建索引时,一个单词会生成好几个索引,而这些索引一定是从头开始
这符合了输入即搜索的特性,即是用户打h、he能找到倒排中的索引h、he,而这些索引对应著的数据就是hello

  • Mapping
    "autocomplete": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "autocomplete_search"
     }
  • Setting
"analysis": {
      "filter": { 
        "my_pinyin": {
          "keep_joined_full_pinyin": "true",
          "keep_full_pinyin": "false"
          "lowercase": "true",
          "keep_original": "true",
          "remove_duplicated_term": "true",
          "keep_separate_first_letter": "false",
          "type": "pinyin",
          "limit_first_letter_length": "16" 
        }
      },
      "analyzer": {
        "autocomplete_search": {
          "filter": [
            "lowercase" ,
            "unique"
          ],
          "tokenizer": "search_py"
        }, 
        "autocomplete": {
          "filter": [
            "lowercase",
            "unique",
            "my_pinyin"
          ],
          "tokenizer": "autocomplete"
        } ,
      "tokenizer": {
        "autocomplete": {
          "min_gram": "1",
          "type": "edge_ngram",
          "max_gram": "16"
        },
        "search_py": { 
          "lowercase": "true",
          "keep_joined_full_pinyin": "true",
          "keep_original": "true",
          "keep_first_letter": "false",
          "keep_separate_first_letter": "false",
          "type": "pinyin",
          "limit_first_letter_length": "16",
          "keep_full_pinyin": "false"
        } 
      }
    }

需要注意的是将keep_full_pinyin置为false,keep_joined_full_pinyin设为true;如果需要支持简拼提示,可将keep_first_letter设为true;开启keep_first_letter支持的提示词输入场景会增多,但同时也会触发一些长尾词效果问题,如输入韩式婚礼,会在候选提示词列表中出现 红色婚礼,原因是他们的简拼都是hshl。同样这些问题在京东PC站也有存在,如果要开启keep_first_letter 就需要对一些长尾词进行容忍:

image.png
  • Query
    通过前缀查询获取提示词列表,并按照搜索量、关联商品数量及相似度分值进行综合打分排序:
{
  "_source": "autocomplete", 
  "query": {
    "script_score": {
      "query": {
         "match_phrase_prefix":{
           "autocomplete":{
             "query":"韩式h",
             "max_expansions":16
           } 
           
         }
      },
      "script": {
        "source": "   Math.log10(doc['count'].value*params.factor1 + 1) + Math.log10(doc['weight'].value * params.factor2 + 1) + _score*params.factor3",
        "params": {
          "factor1": 1,
          "factor2": 2,
          "factor3": 3
        }
      }
    }
  }
}

completion suggester

completion 是ES自带的联想词提示功能,它采用了一种支持快速前缀查找的数据结构,并将数据存储在内存中,检索效率非常高,但缺点也很明显,不能对结果进行自定义排序。

  • Mapping
参数 说明
analyzer 指定索引是分析器,这里我们采用自定义
search_analyzer 指定搜索时使用的分词器 ,各别配置的不同直接决定前端效果
preserve_separators 是否保留分隔符,主要考虑中文提示词 这里不保留
max_input_length 最大提示词输入长度 默认是50,这里设置为16 足够了
     "suggest": {
        "type": "completion",
        "analyzer": "pinyin_analyzer",
        "search_analyzer": "suggest_search",
        "max_input_length": 16,
        "preserve_separators": false
      }

  • Setting
    这里主要依赖elasticsearch pinyin插件:
  "analysis": {
      "filter": {
        "length_filter" : {
              "type" : "length",
              "min" : "2"
            },
        "my_pinyin": {
          "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": "false"
        }
      },
      "analyzer": { 
        "suggest_search": {
          "filter": [
            "lowercase" ,
            "unique"
          ],
          "tokenizer": "suggest_py"
        }, 
        "pinyin_analyzer": {
          "filter": [
            "my_pinyin",
            "lowercase",
            "unique"
          ],
          "tokenizer": "keyword"
        }
      },
      "tokenizer": {  
        "suggest_py": {
          "keep_joined_full_pinyin": "true",
          "keep_none_chinese":"false",
          "keep_none_chinese_in_first_letter ": "false",
          "lowercase": "true",
          "none_chinese_pinyin_tokenize": "false",
          "keep_none_chinese_in_joined_full_pinyin": "true",
          "keep_original": "true",
          "keep_first_letter": "true",
          "keep_separate_first_letter": "false",
          "type": "pinyin",
          "limit_first_letter_length": "16",
          "keep_full_pinyin": "false"
        }
      }
    }

需要注意的是 这里需要将keep_first_letter设置为true ,否则无法进行任意位置的简拼提示;但开启简拼后,需要配合一个好的提示词排序算法,否则就会出现 输入 韩式婚礼 提示 红色婚礼。

其它配置:

keep_first_letter:这个参数会将词的第一个字母全部拼起来.例如:刘德华->ldh.默认为:true
keep_separate_first_letter:这个会将第一个字母一个个分开.例如:刘德华->l,d,h.默认为:flase.如果开启,可能导致查询结果太过于模糊,准确率太低.
limit_first_letter_length:设置最大keep_first_letter结果的长度,默认为:16
keep_full_pinyin:如果打开,它将保存词的全拼,并按字分开保存.例如:刘德华> [liu,de,hua],默认为:true
keep_joined_full_pinyin:如果打开将保存词的全拼.例如:刘德华> [liudehua],默认为:false
keep_none_chinese:将非中文字母或数字保留在结果中.默认为:true
keep_none_chinese_together:保证非中文在一起.默认为: true, 例如: DJ音乐家 -> DJ,yin,yue,jia, 如果设置为:false, 例如: DJ音乐家 -> D,J,yin,yue,jia, 注意: keep_none_chinese应该先开启.
keep_none_chinese_in_first_letter:将非中文字母保留在首字母中.例如: 刘德华AT2016->ldhat2016, 默认为:true
keep_none_chinese_in_joined_full_pinyin:将非中文字母保留为完整拼音. 例如: 刘德华2016->liudehua2016, 默认为: false
none_chinese_pinyin_tokenize:如果他们是拼音,切分非中文成单独的拼音项. 默认为:true,例如: liudehuaalibaba13zhuanghan -> liu,de,hua,a,li,ba,ba,13,zhuang,han, 注意: keep_none_chinese和keep_none_chinese_together需要先开启.
keep_original:是否保持原词.默认为:false
lowercase:小写非中文字母.默认为:true
trim_whitespace:去掉空格.默认为:true
remove_duplicated_term:保存索引时删除重复的词语.例如: de的>de, 默认为: false, 注意:开启可能会影响位置相关的查询.
ignore_pinyin_offset:在6.0之后,严格限制偏移量,不允许使用重叠的标记.使用此参数时,忽略偏移量将允许使用重叠的标记.请注意,所有与位置相关的查询或突出显示都将变为错误,您应使用多个字段并为不同的字段指定不同的设置查询目的.如果需要偏移量,请将其设置为false。默认值:true

  • Query
    completion query根据数据索引时指定的权重值进行排序
 
{
    "suggest" : {
        "input": [ "韩式婚礼", "红色婚礼" ],
        "weight" : 34
    }
}

{ 
  "size": 0,
  "_source": ["autocomplete","weight"], 
  "suggest": {
    "word-suggest": {
      "prefix": "韩式婚礼",
      "completion": {
        "size":5,
        "field": "suggest" 
      }
    }
  }
}

  • 真正到线上应用时可以配合策略两种算法搭配使用,当精确提示返回效果不佳或无提示时,可采用开启简拼的方式进行补充。

提示词关联商品数量

  • 在词条入库前会在商品索引库上执行一次精确查询,返回的total值就是对应的商品数量
  • 为了避免对大搜业务的影响,spark任务会放在凌晨进行
  • 词条的索引Id使用词条的Md5值,便于后期更新处理
  • 为提升效率,应该使用Elasticsearch的Multi Search接口批量进行count,同时批量更新数据库里建议词的count值
  • 在ES 7.x版本想获取total在1w以上的具体值时需 track_total_hits=true
  • 关联商品数量过低的词条会被剔除
  • 由于商品是实时入库的而关联统计是定期离线执行的,所以在进行相关提示时会显示“约”

搜索词推荐

  • 热词推荐
    这里根据提示词库中的weight值排序取Top
 {
   "sort": [
     {
       "weight": {
         "order": "desc"
       }
     }
   ], 
   "query": {
     "match_all": {}
   }
 }

  • 相关搜索词推荐
    基于用户搜索会话日志构建word2vector算法模型,针对搜索提示词入库前,对每一种词条进行关联度预测,获取每个搜索词的最相近的top

输入词意图分析

基于用户的搜索长句,找到最能表达用户搜索意图的核心关键词组;如 电影院影城复工开业活动宣传 -> 电影院复工宣传
意图识别和纠错识别都是基于现有词条实现的,覆盖率与准度受限于提示词库。
大多数情况下我们都是通过输入关键词来查找满足条件的文档,然而意图识别有点类似于给出一段短文本文档来获取满足条件的搜索关键词,通过ES的percolate query可以实现这种反向输入查询。
首先我们需要为每一个词条定义一种查询方式,这里我们统一使用一种query :

{ 
  "query": {
    "span_near": {
      "clauses": [
        {
          "span_term": {
            "txt": {
              "value": "武汉"
            }
          }
        },
        {
          "span_term": {
            "txt": {
              "value": "加油"
            }
          }
        }
      ],
      "slop": 3,
      "in_order": true
    }
  }
}

或者
    {
      "query" : {
            "intervals" : {
              "txt" : {
                "all_of" : {
                  "intervals" : [
                    {
                      "match" : {
                        "ordered" : true,
                        "query" : "高端蓝"
                      }
                    }
                  ]
                }
              }
            }
          }
     }

这里使用的是span_near query,否则 武汉加油 与 加油武汉 都会被 “我们一起为武汉加油” 所召回;具体排序方式以及召回策略可根据具体业务层场景灵活调整,通过slop来调整词的编辑距离 。
同理,分类与品牌词的识别也可以通过这种方式实现,前提是要建立分类与品牌词库。

提示词纠错

用户在PC端通过键盘快速键入关键词搜索时难免输入一些同音或形似错别字,此时如果不作处理的话,用户拿着错误的词很可能检索不到心仪的商品,或者无商品返回,如 黄小明、邀请含等;此时如果能通过搜索提示框帮组用户进行正确的提示,将大大提升用户的查找准度和效率。

{
  "_source": false, 
  "size": 0, 
  "suggest": { 
    "term-suggestion": {
      "text": "邀请含",
     "term": {
       "field": "autocomplete",
       "analyzer":"keyword",
       "min_word_length":2, 
       "prefix_length":1, 
       "size":2
     }
    }
  }
}

参数 说明
analyzer 指定分词器
min_word_length 默认值是4 ,当提示词长度低于4时不作处理,这里改为 2
prefix_length 从什么位置进行错别字识别,这里设置为1
size 返回结果集条目数
sort 需要注意的是返回的结果是按照编辑距离排序 ,也可设置为 frequency 基于文档词频排序

效果

image.png
image.png
image.png
image.png

写在最后

搜索的调优不能一直关注技术方面,还要关注用户。搜索质量的好坏是一个比较主观的评价,想要了解用户是否满意搜索结果,只能通过监测搜索结果和用户的行为,例如用户重复搜索的频率,翻页的频次等。
如果搜索能返回相关性较高的文档,用户应该会在第一次搜索便得到想要的内容,如果返回相关性不太好的结果,用户可能会来回点击或尝试新的搜索条件。
ES是一个通用的搜索框架,想要根据业务实现一个专业的搜索平台,还需要进行很多优化,不仅仅是DSL方面的改变。

附件

完成索引库配置
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356