es深入搜索之多字段搜索

1. 最佳字段

 假设有个网站允许用户搜索博客的内容,以下面两篇博客内容文档为例:

PUT /my_index/my_type/1
{
    "title": "Quick brown rabbits",
    "body":  "Brown rabbits are commonly seen."
}

PUT /my_index/my_type/2
{
    "title": "Keeping pets healthy",
    "body":  "My quick brown fox eats rabbits on a regular basis."
}

 此时用户搜索 " brown fox ",用肉眼判断文档二更匹配。 由于不知道该搜索词出现的字段,所以我们用 bool 查询进行查询。

{
    "query": {
        "bool": {
            "should": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}

  但在返回的结果中文档 1 比 文档 2 的相关度高,因为搜索时,会将每个字段的相关度相加然后计算总评分,文档一的 title 和 body 中都包含 Brown, 所以评分较高,如果不是将每个字段的评分想加,而是将最佳匹配字段的评分作为查询的整体评分,返回的结果将是同时包含 brown 和 fox 的字段所在文档相关度比较高。

  此时应该使用 dis_max 查询,而不是 bool 查询。最大化查询(Disjunction Max Query)指的是: 将任何与查询匹配的文档作为结果返回,但是每个文档的评分都是以最佳匹配的评分作为结果 ,而不是再进行计算。意思是该文档的评分是dis_max下所有查询的评分的最大值,不再进行求和平均计算。

{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}

  由于dis_max会忽略其他匹配查询的分数,可以通过 tie_breaker进行使得其他匹配的分数也参与到计算该文档的评分中。和权重boost不同,权重是字段所占的权重,而tie_breaker是查询所占的权重。

  表示除了最佳匹配,次匹配所占总分比例的 30 %
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Quick pets" }},
                { "match": { "body":  "Quick pets" }}
            ],
            "tie_breaker": 0.3
        }
    }
}

2. 多数字段

  全文搜索被称作是 召回率(Recall) 与 精确率(Precision) 的战场: 召回率 ——返回所有的相关文档; 精确率 ——不返回无关文档。目的是在结果的第一页中为用户呈现最为相关的文档。

  为了提高召回率的效果,我们扩大搜索范围——不仅返回与用户搜索词精确匹配的文档,还会返回我们认为与查询相关的所有文档。如果一个用户搜索 “quick brown box” ,一个包含词语 fast foxes 的文档被认为是非常合理的返回结果。如果有多个文档比该文档更匹配,则该文档出现的位置应该在这些文档之后。

  提高全文相关性精度的常用方式是为同一文本建立多种方式的索引,每种方式都提供了一个不同的相关度信号 signal 。主字段会以尽可能多的形式的去匹配尽可能多的文档。比如我们搜索华为手机,在手机的 desc 字段使用默认分词器,而他的词根 ' 华为手机 ' 不分词。在搜索华为手机时,会将该文档作为结果返回,而他的词根用来提高该文档的相关度。

  对我们的字段索引两次:一次使用词干模式以及一次非词干模式。为了做到这点,采用 multifields 来实现。

PUT /my_index
{
    "settings": { "number_of_shards": 1 }, 
    "mappings": {
        "my_type": {
            "properties": {
                "title": { 
                    "type":     "string",
                    "analyzer": "english",
                    "fields": {
                        "std":   { 
                            "type":     "string",
                            "analyzer": "standard"
                        }
                    }
                }
            }
        }
    }
}

  上例中,给某个字段索引了两次,分别使用了不同的分词器,可以使用广度匹配字段用来匹配更多的数据,用来提升召回率,然后用该字段的词根来将相关度更高的文档置于顶部。

GET /index/_search
{
   "query": {
        "multi_match": {
            "query":       "jumping rabbits",
            "type":        "most_fields",
            "fields":      [ "title", "title.std^10" ] 
        }
    }
}

  跨字段实体搜索,比如人、地址等实体,需要用多个字段来唯一表示一个实体,(last_name、first_name),使用bool查询将会使代码过长,而是用多字段查询又不能完全符合题意。因为多字段搜索是为多数字段是否满足查询条件,不能在所有字段中找到最匹配的、搜索词在多个字段值的出现的频率不一样,会导致结果有误差。

  一种解决方案是增加一个新的字段,比如full_name, 可以使用该字段进行对复杂实体的搜索,但是又会出现冗余数据。es给我们提供了两种解决方案,一个是在索引时,一个是在搜索时。

3. 混合字段

在之前说过, all_filed字段包括了该文档所有值的结合,但是这样并不灵活,我们可以通过copy_to参数人为增加一个all字段,比如下列增加一个full_name字段。

PUT /my_index
{
    "mappings": {
        "person": {
            "properties": {
                "first_name": {
                    "type":     "string",
                    "copy_to":  "full_name" 
                },
                "last_name": {
                    "type":     "string",
                    "copy_to":  "full_name" 
                },
                "full_name": {
                    "type":     "string"
                }
            }
        }
    }
}

  在索引时创建_all字段是一个方案,而es还在搜索时提供了另一种方案,使用 cross_fields 类型进行 multi_match 查询。 cross_fields 使用词中心式(term-centric)的查询方式,这与 best_fields 和 most_fields 使用字段中心式(field-centric)的查询方式非常不同。
  字段中心式:搜索词必须同时出现在同一个字段中。
  词中心式:搜索词必须同时出现,但可以在任意一个字段中。

GET /books/_search
{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "cross_fields", 
            "operator":    "and",
            "fields":      [ "first_name", "last_name" ]
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容