elasticsearch同义词和搜索相关度优化

虽然docker方便.但是由于163镜像版本太低.所以在本地搭了一个es.版本6.3.0;

首先说下这次研究的方向: 搜索框搜西红柿,那么番茄是出不来的. 搜索米的时候.虾米条比大米的相关度还高
暂时考虑的方案如下:
1.加入同义词
2.相关度优化.将字段排优先级,名字的相关度提升
3.未雨绸缪,增加类似某宝某东一样的,销量高的排名也提升一点,具体如下


同义词插件

插件1 :同义词文件配置方式
插件2 :数据库配置方式
原本想使用插件2. 两种方式都是可以动态加载同义词词库.所以配置好之后不需要修改词库就重启es,
但是插件2的大佬一直没有更新,所以我在6.3.0中加入插件报错我没有处理好暂时先使用插件1

插件2
项目支持6.x版本.但是tag上没有,因此clone到本地.修改版本.然后maven打包.得到插件放到es的plugins下重启es
github上有使用的实例.我的测试用例,这个成功之后,暂时先放一边.先搞下相关度优化

DELETE prod
PUT /prod
{
    "index" : {
        "analysis" : {
            "analyzer" : {
                "synonym" : {
                    "tokenizer" : "ik_max_word",
                    "filter" : ["remote_synonym"]
               }
            },
            "filter" : {
                "remote_synonym" : {
                    "type" : "dynamic_synonym",
                    "synonyms_path" : "synonym.txt",    //文件没有就创建一个
                    "interval": 30          //由于本地跑.所以30s重新查一次.线上肯定不可以30s
                },
                "local_synonym" : {
                    "type" : "dynamic_synonym",
                    "synonyms_path" : "synonym.txt"
                }
            }
        }
    }
}


将项目中需要优化的几个字段抽取出来自己定义了一个精简版的demo

PUT /prod/demo/_mapping
{
 
      "properties":{
        "name":{
          "type":"text",
           "analyzer": "synonym"
        },
        "description":{
           "type":"text",
           "analyzer": "ik_max_word"
        },
        "brandName":{
           "type":"text",
           "analyzer": "ik_max_word"
        },
        "labelName": {
           "type": "text",
           "analyzer": "ik_max_word"
        },
         "menuCategoryNamePath": {
           "type": "text",
           "analyzer": "ik_max_word"
        },
        "num":{
          "type": "integer"
        }
  }
}

原先的查询代码:

QueryBuilders.multiMatchQuery(((SearchProductReq) req).getSearchContent(),
                    PRODUCT_NAME,
                    BRAND_NAME,
                    DESCRIPTION,
                    LABEL_NAME,
                    MENU_CATEGORY_NAME_PATH);

等同于:

GET prod/demo/_search
{
  "query":{
    "multi_match": {
      "query": "米",
      "fields": ["name","description","brandName","labelName","menuCategoryNamePath"]
    }
  }
}

修改后,排分还待修正.暂时按这样的分数:

   QueryBuilder  queryBuilder = QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("name", "米").boost(0.8f))
                    .should(QueryBuilders.matchQuery("brandName", "米").boost(0.6f))
                    .should(QueryBuilders.matchQuery("labelName", "米").boost(0.6f))
                    .should(QueryBuilders.matchQuery("menuCategoryNamePath", "米").boost(0.2f))
                    .should(QueryBuilders.matchQuery("description", "米").boost(0.4f));


        FieldValueFactorFunctionBuilder factorFunctionBuilder = new FieldValueFactorFunctionBuilder("num");
        factorFunctionBuilder.factor(0.1f);
        factorFunctionBuilder.modifier(FieldValueFactorFunction.Modifier.LOG1P);
        FunctionScoreQueryBuilder boostMode = QueryBuilders
                .functionScoreQuery(queryBuilder, factorFunctionBuilder)
                .boostMode(CombineFunction.SUM);
        SearchRequestBuilder requestBuilder = client.prepareSearch(ESConstant.PRODUCT_INDEX)
                .setTypes(ESConstant.PRODUCT_TYPE);
        requestBuilder.setQuery(boostMode);

等同于:

GET prod/demo/_search
{
  "query":{
    "function_score": {
      "query": {
          "bool": {
      "should": [
        {
          "match": {
            "name": {"query": "大米","boost":0.8}
          }
        },
        {
          "match": {
            "brandName": {"query": "大米","boost":0.6}
          }
        },
        {
          "match": {
            "labelName": {"query": "大米","boost":0.6}
          }
        },
        {
          "match": {
            "description": {"query": "大米","boost":0.5}
          },
        {
          "match": {
            "menuCategoryNamePath": {"query": "大米","boost":0.2}
          }
        }
      ]
    }
      },
      "field_value_factor": {
        "field": "num",
        "modifier": "log1p",
        "factor": 0.1
      },
      "boost_mode": "sum"
    }
  }
}

提升相关度使用function_score参考官方文档


加入同义词,这个需要修改mapping.

PUT /prod/demo/_mapping
{
 
      "properties":{
        "name":{
          "type":"text",
           "analyzer": "synonym"
        },
        "description":{
           "type":"text",
           "analyzer": "synonym"
        },
        "brandName":{
           "type":"text",
           "analyzer": "synonym"
        },
        "labelName": {
           "type": "text",
           "analyzer": "synonym"
        },
         "menuCategoryNamePath": {
           "type": "text",
           "analyzer": "synonym"
        },
        "num":{
          "type": "integer"
        }
  }
}

这时候在config的synonym.txt文件中增加同义词.比如比如插入数据:


POST /prod/demo/2
{
   "name":"大米",
    "description":"稻香大米",
    "brandName":"COCO",
    "labelName":"大米",
   "menuCategoryNamePath":"食品|饮料",
    "num":3
}
POST /prod/demo/3
{
  "name":"虾米条",
   "description":"虾米条",
    "brandName":"COCO",
    "labelName":"虾米条",
    "menuCategoryNamePath":"食品|零食",
     "num":1
}
POST /prod/demo/4
{
   "name":"惠宜 珍珠米 10KG",
   "description":"惠宜 珍珠米 10KG",
    "brandName":"COCO",
    "labelName":"惠宜",
    "menuCategoryNamePath":"食品|饮料",
     "num":5
}
POST /prod/demo/5
{
   "name":"口口牌 泰国进口 泰国茉莉香米",
   "description":"口口牌 泰国进口 泰国茉莉香米",
    "brandName":"COCO",
    "labelName":"口口牌",
    "menuCategoryNamePath":"食品|饮料",
     "num":3
}

ik分词器不会拆大米.所以大米和米是两个条件. 如果把米/大米设置成近义词.name这时候.搜米和大米都能收到上述商品.并且相关度也有有一定变化.

首先没有淘宝京东那么智能,但是由于我刚接触es.暂时先这样优化下,
测试数据.很假,主要测试下效果.

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