悟空,拿我的打狗棒来
学习排序

学习排序

Day 19 - 通过点击反馈优化es搜索结果排序

Adventlaigood 发表了文章 • 1 个评论 • 5114 次浏览 • 2018-12-19 00:15 • 来自相关话题

      相信不少人都把es当做一个主要的搜索引擎来使用,但是对于搜索结果之后的点击反馈,es没有很好的方案。比如说用户搜索了某些关键词,点击了某些结果,而这些结果并不是排在最前面的,但确实是用户最想要的。那有没有什么方法可以使它们排在前面呢?一种简单的做法就是就是离线统计文档的点击率,然后在排序时根据这个点击率进行加权,但这样笼统的算法不一定适合所有情况。现在就来简单介绍下learning to rank,翻译过来就是学习排序,可以根据点击日志里面的记录,来反向影响搜索结果的排序。刚好这个库也有es的插件,下面以这个插件的官方demo来解释下如何使用。 demo的下载地址如下,都是python脚本,环境需求:python3+,es https://github.com/o19s/elasti ... /demo 1.准备数据 python prepare.py 下载RankLib.jar (用来训练模型) 和tmdb.json (测试数据集,tmdb的电影数据) 2.导测试数据入es python index_ml_tmdb.py 3.训练模型 python train.py 训练脚本很简单,但是脚本里面有丰富的实现,下面介绍下主要方法。 load_features(FEATURE_SET_NAME) 这个是读取特征信息,demo定义了两个特征,分别在1.json
{
    "query": {
        "match": {
            "title": "{{keywords}}"
        }
    }
}
和2.json
{
    "query": {
        "match": {
            "overview": "{{keywords}}"
        }
    }
}
1就是查title,2就是查overview,生成训练数据时就是需要根据特征的查询语法,去es里面匹配相关得分作为特征分数。
movieJudgments = judgments_by_qid(judgments_from_file(filename=JUDGMENTS_FILE))
读取生成训练数据的原始数据,官方称其为决策列表(Judgment list),第一列是数值为0-4的权重,数值越大,相关性越高。回到我们最初的需求就是越多人点击的文档,那么这个权重就越大。第二列是queryid,同次查询结果中的queryid一样,第三列是文档id,这里就是电影id,第四列是文档标题,这里就是电影名。 4   qid:1 #    7555   Rambo 3  qid:1 #    1370   Rambo III 3  qid:1 #    1369   Rambo: First Blood Part II 3  qid:1 #    1368   First Blood 0  qid:1 #    136278 Blood 4  qid:2 #    1366   Rocky 3  qid:2 #    1246   Rocky Balboa 3  qid:2 #    60375  Rocky VI 3  qid:2 #    1371   Rocky III 3  qid:2 #    1375   Rocky V
log_features(es, judgments_dict=movieJudgments, search_index=INDEX_NAME)
build_features_judgments_file(movieJudgments, filename=JUDGMENTS_FILE_FEATURES)
之后就是生成特征集,就是把上面的每条训练数据根据特征查询语句扔进es里面进行查询,把得分放到1和2特征后面,如:下面数据第一条中的,1:12.318446就表示1特征的分数,2:10.573845表示2特征的分数,然后把特征集写到文件。 生成完的特征集如下: 4   qid:1  1:12.318446    2:10.573845 # 7555 rambo 3  qid:1  1:10.357836    2:11.950331 # 1370 rambo 3  qid:1  1:7.0104666    2:11.220029 # 1369 rambo 3  qid:1  1:0.0  2:11.220029 # 1368 rambo 0  qid:1  1:0.0  2:0.0 # 136278 rambo 4  qid:2  1:10.686367    2:8.814796 # 1366  rocky 3  qid:2  1:8.985519 2:9.984467 # 1246  rocky 3  qid:2  1:8.985519 2:8.067647 # 60375 rocky 3  qid:2  1:8.985519 2:5.6604943 # 1371 rocky 3  qid:2  1:8.985519 2:7.3007236 # 1375 rocky 特征集出来后就是训练了,demo提供10总不同的算法,训练好之后把结果传到es提供服务
for modelType in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    # 0, MART
    # 1, RankNet
    # 2, RankBoost
    # 3, AdaRank
    # 4, coord Ascent
    # 6, LambdaMART
    # 7, ListNET
    # 8, Random Forests
    # 9, Linear Regression
    Logger.logger.info("*** Training %s " % modelType)
    train_model(judgments_with_features_file=JUDGMENTS_FILE_FEATURES, model_output='model.txt',
                which_model=modelType)
    save_model(script_name="test_%s" % modelType, feature_set=FEATURE_SET_NAME,       model_fname='model.txt')
4.最后搜索数据 python search.py Rambo 搜索时主要用到了es里面的rescore特性,就是对前面topn条记录根据模型进行再排序,查询dsl如下:
{
  "query": {
      "multi_match": {
          "query": "Rambo",
          "fields": ["title", "overview"]
       }
   },
  "rescore": {
      "query": {
        "rescore_query": {
            "sltr": {
                "params": {
                    "keywords": "Rambo"
                },
                "model": "test_1",
            }
         }
      }
   }
}
得到结果 Rambo Rambo III Rambo: First Blood Part II First Blood In the Line of Duty: The F.B.I. Murders Son of Rambow Spud 当然这个是最简单的一个例子,深入研究可以参考官方文档,很详细:https://elasticsearch-learning ... test/  

Day 19 - 通过点击反馈优化es搜索结果排序

Adventlaigood 发表了文章 • 1 个评论 • 5114 次浏览 • 2018-12-19 00:15 • 来自相关话题

      相信不少人都把es当做一个主要的搜索引擎来使用,但是对于搜索结果之后的点击反馈,es没有很好的方案。比如说用户搜索了某些关键词,点击了某些结果,而这些结果并不是排在最前面的,但确实是用户最想要的。那有没有什么方法可以使它们排在前面呢?一种简单的做法就是就是离线统计文档的点击率,然后在排序时根据这个点击率进行加权,但这样笼统的算法不一定适合所有情况。现在就来简单介绍下learning to rank,翻译过来就是学习排序,可以根据点击日志里面的记录,来反向影响搜索结果的排序。刚好这个库也有es的插件,下面以这个插件的官方demo来解释下如何使用。 demo的下载地址如下,都是python脚本,环境需求:python3+,es https://github.com/o19s/elasti ... /demo 1.准备数据 python prepare.py 下载RankLib.jar (用来训练模型) 和tmdb.json (测试数据集,tmdb的电影数据) 2.导测试数据入es python index_ml_tmdb.py 3.训练模型 python train.py 训练脚本很简单,但是脚本里面有丰富的实现,下面介绍下主要方法。 load_features(FEATURE_SET_NAME) 这个是读取特征信息,demo定义了两个特征,分别在1.json
{
    "query": {
        "match": {
            "title": "{{keywords}}"
        }
    }
}
和2.json
{
    "query": {
        "match": {
            "overview": "{{keywords}}"
        }
    }
}
1就是查title,2就是查overview,生成训练数据时就是需要根据特征的查询语法,去es里面匹配相关得分作为特征分数。
movieJudgments = judgments_by_qid(judgments_from_file(filename=JUDGMENTS_FILE))
读取生成训练数据的原始数据,官方称其为决策列表(Judgment list),第一列是数值为0-4的权重,数值越大,相关性越高。回到我们最初的需求就是越多人点击的文档,那么这个权重就越大。第二列是queryid,同次查询结果中的queryid一样,第三列是文档id,这里就是电影id,第四列是文档标题,这里就是电影名。 4   qid:1 #    7555   Rambo 3  qid:1 #    1370   Rambo III 3  qid:1 #    1369   Rambo: First Blood Part II 3  qid:1 #    1368   First Blood 0  qid:1 #    136278 Blood 4  qid:2 #    1366   Rocky 3  qid:2 #    1246   Rocky Balboa 3  qid:2 #    60375  Rocky VI 3  qid:2 #    1371   Rocky III 3  qid:2 #    1375   Rocky V
log_features(es, judgments_dict=movieJudgments, search_index=INDEX_NAME)
build_features_judgments_file(movieJudgments, filename=JUDGMENTS_FILE_FEATURES)
之后就是生成特征集,就是把上面的每条训练数据根据特征查询语句扔进es里面进行查询,把得分放到1和2特征后面,如:下面数据第一条中的,1:12.318446就表示1特征的分数,2:10.573845表示2特征的分数,然后把特征集写到文件。 生成完的特征集如下: 4   qid:1  1:12.318446    2:10.573845 # 7555 rambo 3  qid:1  1:10.357836    2:11.950331 # 1370 rambo 3  qid:1  1:7.0104666    2:11.220029 # 1369 rambo 3  qid:1  1:0.0  2:11.220029 # 1368 rambo 0  qid:1  1:0.0  2:0.0 # 136278 rambo 4  qid:2  1:10.686367    2:8.814796 # 1366  rocky 3  qid:2  1:8.985519 2:9.984467 # 1246  rocky 3  qid:2  1:8.985519 2:8.067647 # 60375 rocky 3  qid:2  1:8.985519 2:5.6604943 # 1371 rocky 3  qid:2  1:8.985519 2:7.3007236 # 1375 rocky 特征集出来后就是训练了,demo提供10总不同的算法,训练好之后把结果传到es提供服务
for modelType in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    # 0, MART
    # 1, RankNet
    # 2, RankBoost
    # 3, AdaRank
    # 4, coord Ascent
    # 6, LambdaMART
    # 7, ListNET
    # 8, Random Forests
    # 9, Linear Regression
    Logger.logger.info("*** Training %s " % modelType)
    train_model(judgments_with_features_file=JUDGMENTS_FILE_FEATURES, model_output='model.txt',
                which_model=modelType)
    save_model(script_name="test_%s" % modelType, feature_set=FEATURE_SET_NAME,       model_fname='model.txt')
4.最后搜索数据 python search.py Rambo 搜索时主要用到了es里面的rescore特性,就是对前面topn条记录根据模型进行再排序,查询dsl如下:
{
  "query": {
      "multi_match": {
          "query": "Rambo",
          "fields": ["title", "overview"]
       }
   },
  "rescore": {
      "query": {
        "rescore_query": {
            "sltr": {
                "params": {
                    "keywords": "Rambo"
                },
                "model": "test_1",
            }
         }
      }
   }
}
得到结果 Rambo Rambo III Rambo: First Blood Part II First Blood In the Line of Duty: The F.B.I. Murders Son of Rambow Spud 当然这个是最简单的一个例子,深入研究可以参考官方文档,很详细:https://elasticsearch-learning ... test/