IT教程 ·

Elasticsearch系列—深入全文搜索

最通俗易懂的 Java 11 新特性讲解

提要

本篇引见如何在全文字段中搜刮到最相干的文档,包括手动掌握搜刮的精准度,搜刮前提权重掌握。

手动掌握搜刮的精准度

搜刮的两个重要维度:相干性(Relevance)和剖析(Analysis)。

相干性是评价查询前提与效果的相干水平,并对相干水平举行排序,平常运用TF/IDF要领。

剖析是指将索引文档与查询前提规范化的一个历程,目标是竖立倒排索引时,尽量地提拔召回率。

match查询道理

婚配查询match是中心查询语法,它的重要运用场景就是全文搜刮,我们举一个示例:

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "wake"
    }
  }
}

Elasticsearch实行的步骤:

  1. 检索字段范例:match的字段name为text范例,是一个analyzed的字段,那末查询前提的字符串也应该被analyzed。
  2. 剖析查询字符串:将查询字符串"wake"传入分词器中(与mapping的分词器一致),由于只要一个单词,所以match终究实行的是单个底层的term查询。
  3. 查找婚配文档:用term倒排索引中查找wake然后猎取一组包括该词的文档。
  4. 为每一个文档评分:用term查询盘算每一个文档相干度评分,即TF、IDF、length norm算法。

获得的效果以下:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "music",
        "_type": "children",
        "_id": "2",
        "_score": 0.2876821,
        "_source": {
          "id": "a810fad4-54cb-59a1-9b7a-82adb46fa58d",
          "author": "John Smith",
          "name": "wake me, shark me",
          "content": "don't let me sleep too late, gonna get up brightly early in the morning",
          "language": "english",
          "tags": "enlighten",
          "length": 55,
          "isRelease": true,
          "releaseDate": "2019-12-21"
        }
      }
    ]
  }
}

由于样本数据的问题,临时只要一条文档婚配。

搜刮name中包括"you"或"sunshine"的文档

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "you sunshine"
    }
  }
}

搜刮name中包括"you"和"sunshine"的文档

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you sunshine",
        "operator": "and"
      }
    }
  }
}

搜刮精准度掌握的第一步:运用and关键字。假如愿望一切搜刮关键字都要婚配,能够用and来完成。

搜刮"you"、"my"、"sunshine"、"teeth" 4个关键字中,最少包括3个的文档

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}

搜刮精准度掌握的第二步:指定最少婚配个中的多少个关键字,才作为效果返回

bool组合多个搜刮前提

用bool组合,能够完成越发个性化的搜刮需求,比方我们查找称号包括"sunshine",但不包括"teeth",许可涌现"you"、"my"关键字,示例以下:

GET /music/children/_search
{
  "query": {
    "bool": {
      "must":     { "match": { "name": "sunshine" }},
      "must_not": { "match": { "name": "teeth"  }},
      "should": [
                  { "match": { "name": "my" }},
                  { "match": { "name": "you"   }}
      ]
    }
  }
}

should对相干度评分盘算的影响

以上面的bool为例子,我们只议论婚配的文档,按本身的明白,对文档举行大略排名:

  1. 最相符搜刮前提的

文档中同时包括should中的"my"、"you"两个关键字。

  1. 很相符搜刮前提的

文档中包括should中的"my"或"you"两个关键字的个中一个。

  1. 相符搜刮前提的

文档中不包括should中的"my"和"you"。

像must not这类硬性前提,不婚配都不会涌现在效果集里,重要起到消除文档作用,不介入评分盘算。但should也能影响相干度评分,婚配得越多,评分就越高。

bool查询会为每一个文档盘算相干度评分_score ,再将一切婚配的 must 和 should 语句的分数 _score 乞降,末了除以 must 和 should 语句的总数。

这里不细致解说评分盘算的详细细节和分数,相识should对其有影响即可。

should婚配准绳

假如查询前提中有must存在,那末should婚配的数目不作请求;假如没有must,则should必须要婚配一个,要不然满是should前提的,一切文档都能婚配,就失去了搜刮的意义。

假如带上minimum_should_match,那末就能做更邃密的掌握,能够指定必须要婚配几个should,才返回效果集,以下两个示例是同等的:

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}
GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "you" }},
        { "match": { "name": "my"   }},
        { "match": { "name": "sunshine"   }},
        { "match": { "name": "teeth"   }}
      ],
      "minimum_should_match": 3 
    }
  }
}

多词查询的底层道理

上一节当中我们提到的多词match的查询,Elasticsearch会将多词的term查询转换为bool查询,or查询运用should替换, and查询运用must,我们回忆一下上一节的示例:

or查询

下面两个查询是等价的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "you sunshine"
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        {"term": {"name": "you"}},
        {"term": {"name": "sunshine"}}
      ]
    }
  }
}

and查询

下面两个查询也是等价的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you sunshine",
        "operator": "and"
      }
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"name": "you"}},
        {"term": {"name": "sunshine"}}
      ]
    }
  }
}

minimum_should_match语法

下面两个查询仍然是等价的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "you" }},
        { "match": { "name": "my"   }},
        { "match": { "name": "sunshine"   }},
        { "match": { "name": "teeth"   }}
      ],
      "minimum_should_match": 3 
    }
  }
}

minimum_should_match的值能够改,也会依据现实的前提来换算,比方我写个75%,但现实的搜刮词条就只要3个,那末minimum_should_match的值就会变成66.6%,即最少须要婚配2条。

查询语句权重掌握

bool查询里的多前提并列,默许权重是一样的,但现实的搜刮当中,我们可能会迥殊某一些关键词赋予特别的关注,愿望婚配关注度高的文档排序能靠前一些,boost语法能够协助我们完成这一需求。

boost默许是1,能够在查询语句中自行设置,以下示例,我愿望sunshine的权重要大一些:

GET /music/children/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "name": {
            "query": "sunshine",
            "boost": 2
          }
        }
      },
      "should": [
        {
          "match": {
            "name": "my"
          }
        },
        {
          "match": {
            "name": "you"
          }
        }
      ]
    }
  }
}

在查询效果里能够看到,相符前提的文档的_score值变得更高一些。boost值的设置不是简朴的线性增进,boost设置为2不示意_score也会简朴的翻一倍,boost值在盘算时有归一化处置惩罚,但详细的盘算数值及历程不在此篇作细致的诠释。

评分盘算的小问题

我们的演示环境是单node多shard形式的,有些示例发明评分会涌现迥殊高的征象,给人觉得不是很正确,这是为何呢?

不正确的缘由

我们简朴回忆一下评分盘算的几个算法:TF、IDF、Length Norm,个中IDF本意上是在一切的document中,搜刮关键词的涌现次数,现实上IDF默许在当地shard实行的次数统计,一个shard只包括部份数据,不能代表一切数据,如许做比较高效,但会带来误差,也是形成效果不正确的缘由。

演示环境中涌现较大误差,另有一个缘由是演示数据相对较少,假如只要一个document,而且该document相符查询前提,那末IDF的分数就会变得很高。

解决办法

  1. 生产环境数据量相对较大,默许运用_id举行路由,在几率分布下,实在每一个shard的数据基本上比较匀称,不必太忧郁演示环境的这类状况。
  2. 演示环境能够将primary shard设置为1,只要一个shard,那IDF的值肯定是对的。
  3. 演示环境举行搜刮时,带上search_type=dfs_query_then_fetch参数,会将local IDF取出来盘算global IDF。注重机能问题,生产上禁用。

小结

本篇重要引见了全文搜刮几种手动掌握精度的体式格局:逻辑操作符变更、should命中率设置、权重调解等手腕,末了对评分盘算的小问题举行的简朴形貌,感谢。

专注Java高并发、分布式架构,更多手艺干货分享与心得,请关注民众号:Java架构社区
能够扫左侧二维码增加挚友,约请你到场Java架构社区微信群配合讨论手艺

有了这个开源 Java 项目,开发出炫酷的小游戏好像不难?

参与评论