ElasticSearch学习笔记(三)--搜索文档

原创
2018/01/12 15:41
阅读数 520
  • 结构化搜索:非是即否的搜索,要么存于集合之中,要么存在集合之外。结构化查询不关心文件的相关度或评分;只是对文档包括或排除处理。

  • bitset 过滤器会创建一个 bitset (一个包含 0 和 1 的数组),匹配文档的标志位是 1 。例如:[1,0,0,0]

    bitset 可以复用 任何 已使用过的相同过滤器,而无需再次计算整个过滤器。

    这些 bitsets 缓存是“智能”的:它们以增量方式更新。当我们索引新文档时,只需将那些新文档加入已有 bitset,而不是对整个缓存一遍又一遍的重复计算。

    ==这里要搞清楚缓存的是什么==,缓存是类似这种语句的查询{ "term": { "folder": "inbox" }}

    Elasticsearch 会基于使用频次自动缓存查询。如果一个非评分查询在最近的 256 词查询中被使用过(次数取决于查询类型),那么这个查询就会作为缓存的候选。但是,并不是所有的片段都能保证缓存 bitset 。只有那些文档数量超过 10,000 (或超过总文档数量的 3% )才会缓存 bitset 。因为小的片段可以很快的进行搜索和合并,这里缓存的意义不大。

    一旦缓存了,非评分计算的 bitset 会一直驻留在缓存中直到它被剔除。剔除规则是基于 LRU 的:一旦缓存满了,最近最少使用的过滤器会被剔除。

  • 全文搜索 怎样在全文字段中搜索到最相关的文档。全文搜索两个最重要的方面是:相关性(Relevance)分析(Analysis)

一个简单的搜索

搜索姓氏为Smith的员工

GET /employee/doc/_search
{
    "query" : {
        "match" : {
            "last_name" : "Smith"
        }
    },
    "from": 0,
    "size": 2
}

from 显示应该跳过的初始结果数量,默认是0。

size 显示应该返回的结果数,默认是10。

查询语句的结构

{
    QUERY_NAME: {
        ARGUMENT: VALUE,
        ARGUMENT: VALUE,...
    }
}

最重要的查询

  • match_all 匹配所有文档 {"match_all": {}}
  • match 可用的标准查询,

基于全文的查询
如果在一个精确值字段上上使用它, 1 假如数字、日期、布尔或者一个 keyword 字符串字段,那么它将会精确匹配给定的值;2 如果要查询一个( analyzed )已分析的全文字段,它们会先将++查询字符串++传递到一个合适的分析器,然后生成一个供查询的词项列表。

match 查询还可以接受 operator 操作符作为输入参数,默认情况下该操作符是 or。

{
    "query": {
        "match": {
            "title": {      
                "query":    "BROWN DOG!",
                "operator": "and"
            }
        }
    }
}

match 查询支持 minimum_should_match 最小匹配参数, 可以指定必须匹配的词项数用来表示一个文档是否相关。可以将其设置为具体数字或一个百分数。参数 minimum_should_match 的设置非常灵活,可以根据用户输入词项的数目应用不同的规则。具体看这里

{
  "query": {
    "match": {
      "title": {
        "query":                "quick brown dog",
        "minimum_should_match": "75%"
      }
    }
  }
}
  • multi_match 可以在多个字段上执行相同的 match 查询。字段名称可以用模糊匹配的方式给出,例如{"fields": "*_title"}。

multi_match 多匹配查询的类型有多种,其中的三种: best_fields(默认) 、 most_fields 和 cross_fields (最佳字段多数字段跨字段)。

{
    "multi_match": {
        "query":    "full text search",
        "type":     "best_fields",
        "fields":   [ "title", "body" ]
    }
}
  • range 找出那些落在指定区间内的数字或者时间。可用操作符如下: gt, gte, lt, lte
{
    "range": {
        "age": {
            "gte":  20,
            "lt":   30
        }
    }
}

当使用它处理日期字段时, range 查询支持对 日期计算(date math) 进行操作,比方说,如果我们想查找时间戳在过去一小时内的所有文档:

"range" : {
    "timestamp" : {
        "gt" : "now-1h"
    }
}

还可以被应用到某个具体的时间,并非只能是一个像 now 这样的占位符。只要在某个日期后加上一个双管符号 (||) 并紧跟一个日期数学表达式就能做到:

"range" : {
    "timestamp" : {
        "gt" : "2014-01-01 00:00:00",
        "lt" : "2014-01-01 00:00:00||+1M" 
    }
}

详细的日期格式参考https://www.elastic.co/guide/en/elasticsearch/reference/6.1/mapping-date-format.html

  • term 被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者keyword的字符串。它与match的区别是:term查询对于输入的文本不分析,查询那些精确匹配的值(包括在大小写、重音、空格等方面的差异),所以它将给定的值进行精确查询。
  • terms 允许指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件。

一定要了解 term 和 terms 是 包含(contains) 操作,而非 等值(equals) (判断)。

  • exists & missing exists 查询和 missing 查询被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档。相当于SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 。

null, [] (空数组)和 [null] 所有这些都是等价的,它们无法存于倒排索引中。

将多条件组合查询

可以用 bool 查询来将多查询组合在一起,成为想要的布尔查询,它接收以下参数:

  • must 文档 必须 匹配这些条件才能被包含进来。
  • must_not 文档 必须不 匹配这些条件才能被包含进来。
  • should 如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。

所有 must 语句必须匹配,所有 must_not 语句都必须不匹配,但有多少 should 语句应该匹配呢? 默认情况下,没有 should 语句是必须匹配的,只有一个例外:那就是当没有 must 语句的时候,至少有一个 should 语句必须匹配。

  • filter 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

下面是一个组合查询的示例, must,must_not,should的参数可以接收一个数组或一个对象(当只有一个条件时)。

这个查询的意思是查找除名字是john外的姓氏为Smith,年龄大于30的员工,如果员工的兴趣里有music项,这个员工所在的文档的评分会更高。

GET /employee/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "last_name": "smith"
          }
        }
      ],
      "must_not": {
        "match": {
          "first_name": "john"
        }
      },
      "should": [
        {
          "match": {
            "interests": "music"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gt": 30
          }
        }
      }
    }
  }
}

排序与相关性

默认情况下,返回的结果是按照 相关性_score 进行排序的——最相关的文档排在最前。

  • 指定字段行排序
{
    ...
    "sort":{
        "age":{
            "order": "desc"
        }
    }
}

字段排序默认为升序排序,所以如果是按字段升序排序的话,可以用下面的方式简单的指定一个字段

"sort": "age"
  • 多字段排序,可以按如下语法执行
{
    ...
    "sort": [
    {
      "age": {
        "order": "asc"
      }
    },
    {
      "last_name.keyword": {
        "order": "desc"
      }
    }
  ]
}

排序条件的顺序是很重要的。结果首先按第一个条件排序,仅当结果集的第一个 sort 值完全相同时才会按照第二个条件进行排序,以此类推。

  • 多值字段排序

一种情形是字段有多个值的排序, 需要记住这些值并没有固有的顺序;一个多值的字段仅仅是多个值的包装,这时应该选择哪个进行排序呢?

对于数字或日期或keyword,你可以将多值字段减为单值,这可以通过使用 min 、 max 、 avg 或是 sum 排序模式 。

{
    ...
    "sort": [
    {
      "age": {
        "order": "asc"
      }
    },
    {
      "interests.keyword": {
        "order": "asc",
        "mode": "max"
      }
    }
  ]
}

scroll游标查询

可以用来有效地执行大批量的文档查询,而又不用付出深度分页那种代价。 类似传统数据库中的cursor。 游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。

启用游标查询可以通过在查询的时候设置参数 scroll 的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。

GET /old_index/_search?scroll=1m 
{
    "query": { "match_all": {}},
    "sort" : ["_doc"], 
    "size":  1000
}

这个查询的返回结果包括一个字段 _scroll_id, 它是一个base64编码的长字符串 ((("scroll_id"))) 。 现在我们能传递字段 _scroll_id 到 _search/scroll 查询接口获取下一批结果:

GET /_search/scroll
{
    "scroll": "1m", 
    "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs="
}

尽管我们指定字段 size 的值为1000,我们有可能取到超过这个值数量的文档。 当查询的时候, 字段 size作用于单个分片,所以每个批次实际返回的文档数量最大为

size * number_of_primary_shards

使用过滤器

GET /employee/doc/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "last_name.keyword": "Smith"
        }
      },
      "boost": 1.2
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    },
    {
      "interests.keyword": {
        "order": "asc",
        "mode": "max"
      }
    }
  ]
}

几种查询策略

<span id="best_fields"></span>

  • 最佳字段

当搜索词语具体概念的时候,比如 “brown fox” ,词组比各自独立的单词更有意义。像 title 和 body 这样的字段,尽管它们之间是相关的,但同时又彼此相互竞争。文档在 相同字段 中包含的词越多越好,评分也来自于 最匹配字段 。 <span id="most_fields"></span>

  • 多数字段

为了对相关度进行微调,常用的一个技术就是将相同的数据索引到不同的字段,它们各自具有独立的分析链。

主字段可能包括它们的词源、同义词以及 变音词 或口音词,被用来匹配尽可能多的文档。

相同的文本被索引到其他字段,以提供更精确的匹配。一个字段可以包括未经词干提取过的原词,另一个字段包括其他词源、口音,还有一个字段可以提供 词语相似性 信息的瓦片词(shingles)。

其他字段是作为匹配每个文档时提高相关度评分的 信号 , 匹配字段越多 则越好。

<span id="cross_fields"></span>

  • 混合字段

对于某些实体,我们需要在多个字段中确定其信息,单个字段都只能作为整体的一部分:

Person: first_name 和 last_name (人:名和姓) Book: title 、 author 和 description (书:标题、作者、描述) Address: street 、 city 、 country 和 postcode (地址:街道、市、国家和邮政编码) 在这种情况下,我们希望在 任何 这些列出的字段中找到尽可能多的词,这有如在一个大字段中进行搜索,这个大字段包括了所有列出的字段。

短语匹配match_phrase

  • slop参数
  • 邻近度
  • 结果集重新评分 rescore
  • shingles: unigram bigram trigram four-gram five-gram ...

shingles 不仅比短语查询更灵活, 而且性能也更好。

其他几种查询

  • prefix 前缀匹配
  • wildcard 通配符
  • regexp 正则
  • fuzzy 模糊
  • ids 通过给定文档id匹配

边界n-grams(edge n-grams)与自动完成

所谓的边界 n-gram 是相对于shingles来说,它会固定词语开始的一边,以单词 quick 为例,它的边界 n-gram 的结果为:

  • q
  • qu
  • qui
  • quic
  • quick

在索引时配置token过滤器和分析器

PUT /my_index
{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}

然后将分析器应用到指定字段,注意此时分别指定了索引时和查询时的分析器

PUT /my_index/_mapping/my_type
{
    "my_type": {
        "properties": {
            "name": {
                "type":     "string",
                "index_analyzer": "autocomplete",
                "search_analyzer": "standard"
            }
        }
    }
}

更多内容查看https://www.elastic.co/guide/en/elasticsearch/reference/6.1/search-suggesters-completion.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部