Elasticsearch 搜索引擎

Posted ntbww93

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch 搜索引擎相关的知识,希望对你有一定的参考价值。

1. 搜索结果中的一些词的含义

took:整个搜索请求花费了多少毫秒;

hits.total:本次搜索,返回了几条结果;

hits.max_score:本次搜索的所有结果中,最大的相关度分数是多少,每一条document对于search的相关度,越相关,_score分数越大,排位越靠前;

hits.hits:默认查询前10条数据,完整数据,_score降序排序;

shards:shards fail的条件(primary和replica全部挂掉),不影响其他shard。默认情况下来说,一个搜索请求,会打到一个index的所有primary shard上去,每个primary shard都可能会有一个或多个replic shard,所以请求也可以到primary shard的其中一个replica shard上去;

timeout:默认无timeout,latency平衡completeness,手动指定timeout,timeout查询执行机制;

GET /_search?timeout=10m 

timeout查询执行机制指每个shard在timeout时间内,将搜索的部分数据(也可以是全部数据)直接返回给client程序,而不用等到所有的查询结果都查询出来再返回;

2. multi-index和multi-type搜索模式

/_search:所有索引,所有type下的所有数据都搜索出来
/*1,*2/_search:按照通配符去匹配多个索引
/index1,index2/type1,type2/_search:搜索多个index下的多个type的数据
/_all/type1,type2/_search:_all,可以代表搜索所有index下的指定type的数据

3.搜索原理初步

client会把一个请求打到所有primary shard上去执行,因为每个shard都包含了部分数据,所以每个shard都可能包含了搜索请求的结果,因为每个primary shard 都包含replica shard,所以请求也会打到replica shard上。

4.分布搜索

GET /_search?size=10&from=20

5.deep paging 问题 

简单说,就是搜溹的特别深;

带来的问题:coordinate node 上需要保存大量的数据,还需进行大量数据的排序,排序之后再取出对应的那一页,这个过程耗费网络带宽,耗费内存和CPU;

6.query string 基础语法

GET /test_index/test_type/_search?q=test_field:test
GET /test_index/test_type/_search?q=+test_field:test  必须包含和上面一样
GET /test_index/test_type/_search?q=-test_field:test   必须不包含

_all metadata的原理和作用:

我们并不是对document中的每一个field进行一个一个的搜索,_all元数据在建立索引的时候,我们插入一个document,里面包含了多个field,此时es会将里面多个field的值用字符串拼接起来,同时建立索引,我们在不对特定的field的进行搜索的时候,就会从_all field 中进行搜溹;

7.mapping

定义:自动或手动为index中的type建立的一种数据结构和相关配置,简称为mapping;mapping就是index的type的元数据,每个type都有一个自己的mapping,决定了数据类型,建立倒排索引的行为,还有进行搜索的行为;

mapping建立过程:

    1)往es里面直接插入数据,es会自动建立索引,同时建立type以及对应的mapping;
    2)mapping中就自动定义了每个field的数据类型;
    3)不同的数据类型(比如说text和date),可能有的是exact value,有的是full text;
    4)exact value,在建立倒排索引的时候,分词时是将整个值一起作为一个关键词建立到倒排索引中的;full text,会经历处理,分词,normaliztion,才会建立到倒排索引中;
    5)exact value和full text类型的field就决定了,在一个搜索过来的时候,对exact value field或者是full text field进行搜索的行为也是不一样的,会跟建立倒排索引的行为保持一致;比如说exact value搜索的时候,就是直接按照整个值进行匹配,full text,会进行分词和normalization再去倒排索引中去搜索;
    6)可以用es的dynamic mapping,让其自动建立mapping,包括自动设置数据类型;也可以提前手动创建index和type的mapping,自己对各个field进行设置,包括数据类型,包括索引行为,包括分词器等;

dynamic mapping,自动为我们建立index,创建type,以及type对应的mapping,mapping中包含了每个field对应的数据类型,以及如何分词等设置;

true or false --> boolean
123 --> long
123.45 --> double
2017-01-01 --> date
"hello world" --> string/text

mapping的查看:GET /index/_mapping/type

只能创建index时手动建立mapping,或者新增field mapping,但是不能update field mapping;

PUT /website
{
  "mappings": {
    "article": {
      "properties": {
        "author_id": {
          "type": "long"
        },
        "title": {
          "type": "text",
          "analyzer": "english"
        },
        "content": {
          "type": "text"
        },
        "post_date": {
          "type": "date"
        },
        "publisher_id": {
          "type": "text",
          "index": "not_analyzed"
        }
      }
    }
  }
}

es自动建立mapping的时候,设置了不同的field不同的data type。不同的data type的分词、搜索等行为是不一样的。所以出现了_all field和date field的搜索表现完全不一样。

不同类型的field,可能有的就是full text,有的就是exact value;

8.倒排索引

在建立倒排索引前,会先执行一个操作,对拆分出来的单词进行处理(normalization),来提升搜索时能搜到的概率;

9. 分词器

内置的分词器:standard analyzer,simple analyzer,whitespace analyzer,language analyzer

分词器查看 GET /_analyze

10. http协议中get是否可以带上request body

HTTP协议,一般不允许get请求带上request body,但是因为get更加适合描述查询数据的操作,因此还是这么用了;

GET /_search?from=0&size=10

POST /_search
{
"from":0,
"size":10
}

11. Query DSL的基本语法

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

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

GET /test_index/test_type/_search 
{
  "query": {
    "match": {
      "test_field": "test"
    }
  }
}

组合搜索条件:

搜索需求:title必须包含elasticsearch,content可以包含elasticsearch也可以不包含,author_id必须不为111
GET /website/article/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "elasticsearch"
          }
        }
      ],
      "should": [
        {
          "match": {
            "content": "elasticsearch"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "author_id": 111
          }
        }
      ]
    }
  }
}

12. filter实例

filter,仅仅只是按照搜索条件过滤出需要的数据而已,不计算任何相关度分数,对相关度没有任何影响;
query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序;

一般来说,如果你是在进行搜索,需要将最匹配搜索条件的数据先返回,那么用query;如果你只是要根据一些条件筛选出一部分数据,不关注其排序,那么用filter
除非是你的这些搜索条件,你希望越符合这些搜索条件的document越排在前面返回,那么这些搜索条件要放在query中;如果你不希望一些搜索条件来影响你的document排序,那么就放在filter中即可;

filter与query性能对比:
filter,不需要计算相关度分数,不需要按照相关度分数进行排序,同时还有内置的自动cache最常使用filter的数据;
query,相反,要计算相关度分数,按照分数进行排序,而且无法cache结果

GET /company/employee/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "join_date": "2016-01-01"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 30
          }
        }
      }
    }
  }
}

13. query搜索语法

1)、match all

GET /_search
{
    "query": {
        "match_all": {}
    }
}

2)、match

GET /_search
{
    "query": { "match": { "title": "my elasticsearch article" }}
}

3)、multi match

GET /test_index/test_type/_search
{
  "query": {
    "multi_match": {
      "query": "test",
      "fields": ["test_field", "test_field1"]
    }
  }
}

4)、range query

GET /company/employee/_search 
{
  "query": {
    "range": {
      "age": {
        "gte": 30
      }
    }
  }
}

5)、term query

GET /test_index/test_type/_search 
{
  "query": {
    "term": {
      "test_field": "test hello"
    }
  }
}

6)、terms query

GET /_search
{
    "query": { "terms": { "tag": [ "search", "full_text", "nosql" ] }}
}

14. 快速验证错误原因

GET /test_index/test_type/_validate/query?explain

{
"query": {
"math": {
"test_field": "test"
}
}
}

15.排序规则

1)默认情况下是有按照score进行降序排序的,对比没有score时(filter),可以使用constant_score

GET /_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "term" : {
                    "author_id" : 1
                }
            }
        }
    }
}

2) 定制排序规则:

GET /company/employee/_search 
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "age": {
            "gte": 30
          }
        }
      }
    }
  },
  "sort": [
    {
      "join_date": {
        "order": "asc"
      }
    }
  ]
}

16. TF-IDF算法

Term frequency(TF):搜索文本中的各个词条在field文本中出现了多少次,出现次数越多,就越相关;

Inverse document frequency(IDF):搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,就越不相关;

Field-length norm:field长度,field越长,相关度越弱;

1)_score是如何被计算出来的?

GET /test_index/test_type/_search?explain
{
  "query": {
    "match": {
      "test_field": "test hello"
    }
  }
}

2)分析一个document是如何被匹配上的

GET /test_index/test_type/6/_explain
{
  "query": {
    "match": {
      "test_field": "test hello"
    }
  }
}

17. doc values

搜索的时候,要依靠倒排索引;排序的时候,需要依靠正排索引(doc values)

doc values是被保存在磁盘上的,此时如果内存足够,os会自动将其缓存在内存中,性能还是会很高;如果内存不足够,os会将其写入磁盘上;

18. query phase

1)搜索请求发送到某一个coordinate node,构建一个priority queue,长度以paging操作from和size为准,默认为10;
2)coordinate node将请求转发到所有shard,每个shard本地搜索,并构建一个本地的priority queue;
3)各个shard将自己的priority queue返回给coordinate node,并构建一个全局的priority queue;

replica shard如何提升搜索吞吐量?

一次请求要打到所有shard的一个replica/primary上去,如果每个shard都有多个replica,那么同时并发过来的搜索请求可以同时打到其他的replica上去;

19. fetch phase

1)在query phase结束时,coordinate node构建完全局priority queue之后,就发送mget请求去所有shard上获取对应的document;
2)各个shard将document返回给coordinate node;
3)coordinate node将合并后的document结果返回给client客户端;

一般搜索,如果不加from和size,就默认搜索前10条,按照_score排序;

20. 参数preference,search_type

1)决定了哪些shard会被用来执行搜索操作

_primary, _primary_first, _local, _only_node:xyz, _prefer_node:xyz, _shards:2,3

2)bouncing results问题

两个document排序,field值相同;不同的shard上,可能排序不同;每次请求轮询打到不同的replica shard上;每次页面上看到的搜索结果的排序都不一样。这就是bouncing result,也就是跳跃的结果。

解决方案就是将preference设置为一个字符串,比如说user_id,让每个user每次搜索的时候,都使用同一个replica shard去执行,就不会看到bouncing results;

3)search_type

default:query_then_fetch
dfs_query_then_fetch,可以提升revelance sort精准度

21. scoll技术

scoll滚动查询,一批一批的查,直到所有数据都查询完处理完;

scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的;
采用基于_doc进行排序的方式,性能较高;
每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内能完成就可以了;

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

获得的结果会有一个scoll_id,下一次再发送scoll请求的时候,必须带上这个scoll_id

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















































以上是关于Elasticsearch 搜索引擎的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch:如何在 Elasticsearch 中正确使用同义词功能

elasticsearch代码片段,及工具类SearchEsUtil.java

Elasticsearch--搜索

小烨收藏ElasticSearch权威指南-入门

ElasticSearch 学习笔记一 简介

ES问题