美文网首页
elasticsearch 学习笔记3

elasticsearch 学习笔记3

作者: 第八共同体 | 来源:发表于2017-12-13 15:48 被阅读0次

    1.分页

    image.png
    举个例子,上面的_search查询中,total给出数据的总量,但是,实际显示出来的只有10条。那么,如果我们显示更多的数据呢
    和 SQL 使用 LIMIT 关键字返回单个 page 结果的方法相同,Elasticsearch 接受 fromsize 参数:
    size显示应该返回的结果数量,默认是10
    from 显示应该跳过的初始结果数量,默认是0
    如果每页展示 5 条结果,可以用下面方式请求得到 1 到 3 页的结果:
    GET /_search?size=5
    GET /_search?size=5&from=5
    GET /_search?size=5&from=10
    

    理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给协调节点,协调节点对 50 个结果排序得到全部结果的前 10 个。

    现在假设我们请求第 1000 页--结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。

    可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因

    2. 映射和分析

    当摆弄索引里面的数据时,我们发现一些奇怪的事情。一些事情看起来被打乱了:在我们的索引中有12条推文,其中只有一条包含日期 2014-09-15 ,但是看一看下面查询命中的 总数 (total):

    GET /_search?q=2014              # 12 results
    GET /_search?q=2014-09-15        # 12 results !
    GET /_search?q=date:2014-09-15   # 1  result
    GET /_search?q=date:2014         # 0  results !
    

    为什么在_all字段查询日期返回所有推文,而在 date 字段只查询年份却没有返回结果?为什么我们在 _all 字段和 date 字段的查询结果有差别?
    推测起来,这是因为数据在 _all 字段与 date 字段的索引方式不同。所以,通过请求 gb 索引中 tweet 类型的映射(或模式定义),让我们看一看 Elasticsearch 是如何解释我们文档结构的:

    GET /gb/_mapping/tweet
    

    结果:

    {
       "gb": {
          "mappings": {
             "tweet": {
                "properties": {
                   "date": {
                      "type": "date",
                      "format": "strict_date_optional_time||epoch_millis"
                   },
                   "name": {
                      "type": "string"
                   },
                   "tweet": {
                      "type": "string"
                   },
                   "user_id": {
                      "type": "long"
                   }
                }
             }
          }
       }
    }
    

    基于对字段类型的猜测, Elasticsearch 动态为我们产生了一个映射。这个响应告诉我们date字段被认为是date类型的。由于_all是默认字段,所以没有提及它。但是我们知道_all字段是string类型的。所以date字段和string字段索引方式不同,因此搜索结果也不一样。这完全不令人吃惊。你可能会认为核心数据类型 strings、numbers、Booleans 和 dates 的索引方式有稍许不同。没错,他们确实稍有不同。

    但是,到目前为止,最大的差异在于代表精确值(它包括string字段)的字段和代表全文的字段。这个区别非常重要——它将搜索引擎和所有其他数据库区别开来。

    3.精确值和全文

    Elasticsearch 中的数据可以概括的分为两类:精确值和全文。 精确值 如它们听起来那样精确。 例如日期或者用户 ID,但字符串也可以表示精确值,例如用户名或邮箱地址。对于精确值来讲,Foofoo是不同的,20142014-09-15也是不同的。另一方面,全文是指文本数据(通常以人类容易识别的语言书写),例如一个推文的内容或一封邮件的内容.
    精确值很容易查询。结果是二进制的:要么匹配查询,要么不匹配。查询全文数据要微妙的多。我们问的不只是“这个文档匹配查询吗”,而是“该文档匹配查询的程度有多大?”换句话说,该文档与给定查询的相关性如何?我们很少对全文类型的域做精确匹配。相反,我们希望在文本类型的域中搜索。为了促进这类在全文域中的查询,Elasticsearch 首先 分析 文档,之后根据结果创建 倒排索引 。

    4.倒排索引

    例如,假设我们有两个文档,每个文档的content域包含如下内容:

      1. The quick brown fox jumped over the lazy dog
      1. Quick brown foxes leap over lazy dogs in summer

    为了创建倒排索引,我们首先将每个文档的content域拆分成单独的词(我们称它为词条tokens),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。结果如下所示:

    Term      Doc_1  Doc_2
    -------------------------
    Quick   |       |  X
    The     |   X   |
    brown   |   X   |  X
    dog     |   X   |
    dogs    |       |  X
    fox     |   X   |
    foxes   |       |  X
    in      |       |  X
    jumped  |   X   |
    lazy    |   X   |  X
    leap    |       |  X
    over    |   X   |  X
    quick   |   X   |
    summer  |       |  X
    the     |   X   |
    ------------------------
    

    现在,如果我们想搜索 quick brown ,我们只需要查找包含每个词条的文档:

    Term      Doc_1  Doc_2
    -------------------------
    brown   |   X   |  X
    quick   |   X   |
    ------------------------
    Total   |   2   |  1
    

    两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单相似性算法,那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳。但是,我们目前的倒排索引有一些问题:

    • Quick 和 quick 以独立的词条出现,然而用户可能认为它们是相同的词。
    • fox 和 foxes 非常相似, 就像 dog 和 dogs ;他们有相同的词根。
    • jumped 和 leap, 尽管没有相同的词根,但他们的意思很相近。他们是同义词。

    使用前面的索引搜索 +Quick +fox 不会得到任何匹配文档。(记住,+ 前缀表明这个词必须存在。)只有同时出现 Quick 和 fox 的文档才满足这个查询条件,但是第一个文档包含 quick fox ,第二个文档包含 Quick foxes 。我们的用户可以合理的期望两个文档与查询匹配。我们可以做的更好。如果我们将词条规范为标准模式,那么我们可以找到与用户搜索的词条不完全一致,但具有足够相关性的文档。例如:

    • Quick 可以小写化为 quick 。
    • foxes 可以 词干提取 --变为词根的格式-- 为 fox 。类似的, dogs 可以为提取为 dog 。
    • jumped 和 leap 是同义词,可以索引为相同的单词 jump 。

    现在索引看上去像这样:

    Term      Doc_1  Doc_2
    -------------------------
    brown   |   X   |  X
    dog     |   X   |  X
    fox     |   X   |  X
    in      |       |  X
    jump    |   X   |  X
    lazy    |   X   |  X
    over    |   X   |  X
    quick   |   X   |  X
    summer  |       |  X
    the     |   X   |  X
    ------------------------
    

    这还远远不够。我们搜索 +Quick +fox 仍然 会失败,因为在我们的索引中,已经没有 Quick 了。但是,如果我们对搜索的字符串使用与 content 域相同的标准化规则,会变成查询 +quick +fox ,这样两个文档都会匹配!

    5.分析和分析器

    分析包含下面的过程:

    • 首先,将一块文本分成适合于倒排索引的独立的 词条
    • 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall

    分析器执行上面的工作。分析器实际上是将三个功能封装到了一个包里:
    字符过滤器
    首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and
    分词器
    其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
    Token 过滤器
    最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 aandthe 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。
    Elasticsearch提供了开箱即用的字符过滤器、 分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。我们会在
    自定义分析器 章节详细讨论。

    5.1 内置的分析器

    但是, Elasticsearch还附带了可以直接使用的预包装的分析器。 接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:
    "Set the shape to semi-transparent by calling set_trans(5)"
    标准分析器
    标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据Unicode 联盟定义的单词边界划分文本。删除绝大部分标点。最后,将词条小写。它会产生
    set, the, shape, to, semi, transparent, by, calling, set_trans, 5
    简单分析器
    简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生
    set, the, shape, to, semi, transparent, by, calling, set, trans
    空格分析器
    空格分析器在空格的地方划分文本。它会产生
    Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
    语言分析器
    特定语言分析器可用于很多语言。它们可以考虑指定语言的特点。例如,英语分析器附带了一组英语无用词(常用单词,例and或者the,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的词干英语分词器会产生下面的词条:
    set, shape, semi, transpar, call, set_tran, 5
    注意看
    transparentcallingset_trans已经变为词根格式。

    5.2什么时候使用分析器

    当我们索引一个文档,它的全文域被分析成词条以用来创建倒排索引。但是,当我们在全文域搜索的时候,我们需要将查询字符串通过
    相同的分析过程,以保证我们搜索的词条格式与索引中的词条格式一致。全文查询,理解每个域是如何定义的,因此它们可以做正确的事:

    • 当你查询一个全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。
    • 当你查询一个精确值 域时,不会分析查询字符串,而是搜索你指定的精确值。

    现在你可以理解在开始的查询为什么返回那样的结果:

    • date 域包含一个精确值:单独的词条 2014-09-15
    • _all 域是一个全文域,所以分词进程将日期转化为三个词条: 201409, 和 15

    当我们在_all域查询2014,它匹配所有的12条推文,因为它们都含有 2014
    当我们在 _all 域查询 2014-09-15,它首先分析查询字符串,产生匹配201409, 或15 中 任意 词条的查询。这也会匹配所有12条推文,因为它们都含有 2014 ,
    当我们在 date 域查询 2014-09-15,它寻找 精确 日期,只找到一个推文,
    当我们在 date 域查询 2014,它找不到任何文档,因为没有文档含有这个精确日志

    相关文章

      网友评论

          本文标题:elasticsearch 学习笔记3

          本文链接:https://www.haomeiwen.com/subject/yjxzixtx.html