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"
}