Elasticsearch 学习笔记


启动
./bin/elasticsearch

索引一条数据
curl  -XPUT 'localhost:9200/megacorp/employee/3' -d '
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}'

「索引」含义的区分
你可能已经注意到索引(index)这个词在Elasticsearch中有着不同的含义,所以有必要在此做一下区分:
1 索引(名词) 如上文所述,一个索引(index)就像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是 indices 或 indexes 。
2 索引(动词) 「索引一个文档」表示把一个文档存储到索引(名词)里,以便它可以被检索或者查询。
这很像SQL中的 INSERT 关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。
3 倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。
Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。



---------------------------------------检索简介--------------------------------------------------
检索文档
curl  -XGET 'localhost:9200/megacorp/employee/1'

简单搜索
curl  -XGET 'localhost:9200/megacorp/employee/_search'
curl  -XGET 'localhost:9200/megacorp/employee/_search?q=last_name:Smith'


使用DSL语句查询

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "match" : {
            "last_name" : "Smith"
        }
    }
}'

复杂的搜索 过滤器(filter)

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "filtered" : {
            "filter" : {
                "range" : {
                    "age" : { "gt" : 30 }
                }
            },
            "query" : {
                "match" : { "last_name" : "smith" }
            }
        }
    }
}'


全文搜索

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "match" : {
            "about" : "rock climbing"
        }
    }
}'


这个例子很好的解释了Elasticsearch如何在各种文本字段中进行全文搜索,并且返回相关性最大的结果集

短语搜索

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    }
}'


确切的匹配若干个单词或者短语(phrases)

高亮我们的搜索


curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "fields" : {
            "about" : {}
        }
    }
}'

---------------------------------------聚合(aggregations)--------------------------------------------------

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "interests" }
    }
  }
}'

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
  "query": {
    "match": {
      "last_name": "smith"
    }
  },
  "aggs": {
    "all_interests": {
      "terms": {
        "field": "interests"
      }
    }
  }
}'

curl  -XGET 'localhost:9200/megacorp/employee/_search' -d '
{
    "aggs" : {
        "all_interests" : {
            "terms" : { "field" : "interests" },
            "aggs" : {
                "avg_age" : {
                    "avg" : { "field" : "age" }
                }
            }
        }
    }
}'


分布式特性
Elasticsearch致力于隐藏分布式系统的复杂性。以下这些操作都是在底层自动完成的:
1 将你的文档分区到不同的容器或者分片(shards)中,它们可以存在于一个或多个节点中。
2 将分片均匀的分配到各个节点,对索引和搜索做负载均衡。
3 冗余每一个分片,防止硬件故障造成的数据丢失。
4 将集群中任意一个节点上的请求路由到相应数据所在的节点。
5 无论是增加节点,还是移除节点,分片都可以做到无缝的扩展和迁移。

--------------分布式集群------------


一个节点(node)就是一个Elasticsearch实例,而一个集群(cluster)由一个或多个节点组成,它们具有相同的cluster.name,它们协同工作,分享数据和负载。


做为用户,我们能够与集群中的任何节点通信,包括主节点。每一个节点都知道文档存在于哪个节点上,它们可以转发请求到相应的节点上。
我们访问的节点负责收集各节点返回的数据,最后一起返回给客户端。这一切都由Elasticsearch处理。

------集群健康------
curl  -XGET 'localhost:9200/_cluster/health'

green 所有主要分片和复制分片都可用
yellow 所有主要分片可用,但不是所有复制分片都可用
red 不是所有的主要分片都可用

------添加索引------
一个分片(shard)是一个最小级别 "工作单元(worker unit)" ,它只是保存了索引中所有数据的一部分。

我们的文档存储在分片中,并且在分片中被索引,但是我们的应用程序不会直接与它们通信,取而代之的是,直接与索引通信。

分片可以是主分片(primary shard)或者是复制分片(replica shard)
curl  -XPUT 'localhost:9200/blogs' -d '
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}'


在同一个节点上保存相同的数据副本是没有必要的,如果这个节点故障了,那所有的数据副本也会丢失。

Elasticsearch是一个分布式的文档(document)存储引擎。
它可以实时存储并检索复杂数据结构——序列化的JSON文档。
换言说,一旦文档被存储在Elasticsearch中,它就可以在集群的任一节点上被检索。

在Elasticsearch中,每一个字段的数据都是默认被索引的。


3.1 索引
_index  类似关系数据库的数据库
_type   类似关系数据库的表
_id     类似关系数据库的主键

PUT /{index}/{type}/{id}
{
  "field": "value",
  ...
}


id可以自动生成

3.2 获取数据

curl  -XGET 'localhost:9200/megacorp/employee/1?pretty'

pretty参数 :在任意的查询字符串中增加pretty参数,类似于上面的例子。会让Elasticsearch美化输出(pretty-print)JSON响应以便更加容易阅读。


通常,GET请求将返回文档的全部,存储在_source参数中。
请求个别字段可以使用_source参数,多个字段可以使用逗号分隔
curl  -XGET 'localhost:9200/megacorp/employee/1?pretty&_source=first_name,last_name'


只想得到_source字段
curl  -XGET 'localhost:9200/megacorp/employee/1/_source'

检查文档是否存在
curl -i -XHEAD 'localhost:9200/megacorp/employee/1'


这只表示你在查询的那一刻文档不存在

--------创建一个新文档
curl  -XPUT 'localhost:9200/megacorp/employee/3?op_type=create'  -d '
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}'

curl  -XPUT 'localhost:9200/megacorp/employee/4/_create'  -d '
{
    "first_name" :  "Douglas",
    "last_name" :   "Fir",
    "age" :         35,
    "about":        "I like to build cabinets",
    "interests":  [ "forestry" ]
}'


删除文档
curl  -XDELETE 'localhost:9200/megacorp/employee/4'


即使文档不存在——"found"的值是false——_version依旧增加了。
这是内部记录的一部分,它确保在多节点间不同操作可以有正确的顺序。

并发控制-处理冲突
乐观并发控制
_version保证所有修改都被正确排序
利用_version的这一优点确保数据不会因为修改冲突而丢失。
我们可以指定文档的version来做想要的更改。
如果那个版本号不是现在的,我们的请求就失败了。

检索多个文档
_mget

批量操作
_bulk

-------分布式-----
当我们发送请求,最好的做法是循环通过所有节点请求,这样可以平衡负载。


新建、索引和删除请求都是写(write)操作,它们必须在主分片上成功完成才能复制到相关的复制分片上。


routing
replication
consistency

timeout


批量格式
Elasticsearch则是从网络缓冲区中一行一行的直接读取数据。它使用换行符识别和解析action/metadata行,以决定哪些分片来处理这个请求。
这些行请求直接转发到对应的分片上。这些没有冗余复制,没有多余的数据结构。整个请求过程使用最小的内存在进行。

--------搜索------------
每个文档里的字段都会被索引并被查询。
在简单查询时,Elasticsearch可以使用所有的索引,以非常快的速度返回结果。这让你永远不必考虑传统数据库的一些东西。


映射(Mapping) 数据在每个字段中的解释说明
分析(Analysis) 全文是如何处理的可以被搜索的
领域特定语言查询(Query DSL) Elasticsearch使用的灵活的、强大的查询语言


空搜索


多索引和多类别


curl  -XGET 'localhost:9200/megacorp/employee/_search?q=+first_name:Jane+last_name:Smith'

curl  -XGET 'localhost:9200/megacorp/employee/_search?q=Smith'



*** _all字段
Elasticsearch把所有字符串字段值连接起来放在一个大字符串中,它被索引为一个特殊的字段_all

复杂的查询
使用_all的复杂查询
_all field
name字段包含"mary"或"john"
date晚于2014-09-10
_all字段包含"aggregations"或"geo"
+name:(mary john) +date:>2014-09-10 +(aggregations geo)


**查询字符串搜索允许任意用户在索引中任何一个字段上运行潜在的慢查询语句,可能暴露私有信息甚至使你的集群瘫痪。**

------映射和分析------

映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型(string, number, booleans, date等)。


分析(analysis)机制用于进行全文文本(Full Text)的分词,以建立供搜索用的反向索引。

index 参数控制字符串以何种方式被索引
{
	"tag": {
		"type": "string",
		"index": "not_analyzed"   
	}
}


analyzed       首先分析这个字符串,然后索引。换言之,以全文形式索引此字段。
not_analyzed   索引这个字段,使之可以被搜索,但是索引内容和指定值一样。不分析此字段。
no             不索引这个字段。这个字段不能为搜索到。

对于analyzed类型的字段


确切值(Exact values) vs. 全文文本(Full text)




**
分析(analysis)是分析器(analyzer)完成的。
一个分析器(analyzer)只是一个包装用于将三个功能放到一个包里
1 字符过滤器  首先字符串经过字符过滤器(character filter),它们的工作是在表征化(断词)前处理字符串。字符过滤器能够去除HTML标记,或者转换 "&" 为 "and" 。
2 分词器      被表征化(断词)为独立的词。一个简单的分词器(tokenizer)可以根据空格或逗号将单词分开(这个在中文中不适用)。
3 表征过滤    最后,每个词都通过所有表征过滤(token filters),
             它可以修改词(例如将 "Quick" 转为小写),去掉词(例如停用词像 "a" 、 "and"``"the" 等等),或者增加词(例如同义词像 "jump" 和 "leap" )


Elasticsearch提供很多开箱即用的字符过滤器,分词器和表征过滤器。这些可以组合来创建自定义的分析器以应对不同的需求。


内建的分析器
1 标准分析器
2 简单分析器
3 空格分析器
4 语言分析器

测试分析器
curl  -XGET 'localhost:9200/_analyze?analyzer=standard'

指定分析器

自动探测字段的情况:
当Elasticsearch在你的文档中探测到一个新的字符串字段,它将自动设置它为全文 string 字段并用 standard 分析器分析。


所以需要人工映射字段

当你索引一个包含新字段的文档(一个之前没有的字段)
Elasticsearch将使用动态映射猜测字段类型,这类型来自于JSON的基本数据类型,使用以下规则:
Boolean: true or false			"boolean"
Whole number: 123			"long"
Floating point: 123.45			"double"
String, valid date: "2014-09-15"	"date"
String: "foo bar"			"string"

增加新的映射字段
PUT /gb/_mapping/tweet
{
	"properties" : {
		"tag" : {
		"type" : "string",
		"index": "not_analyzed"
		}
	}
}


你可以在第一次创建索引的时候指定映射的类型。此外,你也可以晚些时候为新类型添加映射
你可以向已有映射中增加字段,但你不能修改它。
如果一个字段在映射中已经存在,这可能意味着那个字段的数据已经被索引。
如果你改变了字段映射,那已经被索引的数据将错误并且不能被正确的搜索到。
****我们可以更新一个映射来增加一个新字段,但是不能把已有字段的类型那个从 analyzed 改到 not_analyzed 。(修改了之后数据不会按照原有想法被查询到)

查看映射

curl  -XGET 'localhost:9200/megacorp/_mapping/employee/'

** 复合核心字段类型


1 数组  :对于数组不需要特殊的映射。任何一个字段可以包含零个、一个或多个值,同样对于全文字段将被分析并产生多个词。
        数组中所有值必须为同一类型,索引是没有顺序的,在搜索阶段你不能指定"第一个值"或者"最后一个值"。


2 空字段  Lucene没法存放 null 值,所以一个 null 值的字段被认为是空字段。
        这四个字段将被识别为空字段而不被索引:
"empty_string": "",
"null_value": null,
"empty_array": [],
"array_with_null_value": [ null ]

3 内部对象 - 如何被索引 - 扁平化文件


{
    "tweet": "Elasticsearch is very flexible",
    "user": {
        "id": "@johnsmith",
        "gender": "male",
        "age": 26,
        "name": {
            "full": "John Smith",
            "first": "John",
            "last": "Smith"
        }
    }
}

索引的时候,一个 Lucene 文件包含一个键-值对应的扁平表单。
"user.name.full": [john, smith],
"user.name.first": [john],
"user.name.last": [smith]

********查询与过滤


** 结构化查询 DSL
1. 查询字句
{
    "query": {
        "match": {
            "tweet": "elasticsearch"
        }
    }
}

2. 合并多个字句  : 以合并简单的子句为一个复杂的查询语句
{
	"bool": {
	   "must": { "match": { "tweet": "elasticsearch" }},
	   "must_not": { "match": { "name": "mary" }}, 
	   "should": { "match": { "tweet": "full text" }}
	}
}

** 查询与过滤
过滤语句会询问每个文档的字段值是否包含着特定值
        查询语句会询问每个文档的字段值与特定值的匹配程度如何
重点:      
做精确匹配搜索时,你最好用过滤语句,因为过滤语句可以缓存数据

** 过滤
1 term 过滤
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串

	{ "term": { "age": 26 }}

精准查找使用过滤器,过滤器的重要性在于它们非常的快。


过滤器顺序
假如条件 A 匹配 1000 万个文档,而 B 只匹配 100 个文档,那么需要将 B 放在 A 前面。


term 过滤器本身并不能起作用,为了使用 term 过滤器,我们需要将它包含在一个过滤查询语句中:
{
    "query": {
        "filtered": {  -- filtered 查询同时接受接受 query 与 filter
            "query": {
                "match_all": { }  -- match_all 用来匹配所有文档
            },
            "filter": {
                "term": {  -- term 过滤器
                    "price": 20
                }
            }
        }
    }
}

term过滤字符串的时候,字段需要为 not_analyzed

2 terms 过滤
{
    "terms": {
        "tag": [ "search", "full_text", "nosql" ]
    }
}



-- 完整的,也要放在 filtered 查询中
{
    "query": {
        "filtered": {
            "filter": {
                "terms": {
                    "price": [ 20, 30 ]
                }
            }
        }
    }
}

3 range 过滤
{
    "range": {
        "age": {
            "gte": 20,
            "lt": 30
        }
    }
}


支持日期数学操作
{
    "range": {
        "timestamp": {
            "gt": "now-1h"   -- 找出所有时间戳大于当前时间减 1 小时的文档
        }
    }
}


"2014-01-01 00:00:00||+1M" : 2014 年 1 月 1 号加一个月

4 exists 和 missing 过滤


{
    "exists": {
        "field": "title"
    }
}


只是针对已经查出一批数据来,但是想区分出某个字段是否存在的时候使用


5 bool 过滤  来合并多个过滤条件查询结果的布尔逻辑
must        :and   
must_not    :not
should      :or

{
	"bool": {
	  "must": { "term": { "folder": "inbox" }},
	  "must_not": { "term": { "tag": "spam" }},
	  "should": [
		{ "term": { "starred": true }},
		{ "term": { "unread": true }}
	  ]
	}
}

** 查询


1 match_all 查询


2 match 查询


match 查询一个全文本字段
{
    "match": {
        "tweet": "About Search"
    }
}


match 下指定了一个确切值

{ "match": { "age": 26 }}


3 multi_match 查询 

{
    "multi_match": {
        "query": "full text search",
        "fields": [ "title", "body" ]
    }
}


同时搜索title 和 body 这2个字段


4 bool 查询   合并多个查询子句


{
    "bool": {
        "must": {
            "match": {  "title": "how to make millions" }
        },
        "must_not": {
            "match": { "tag": "spam"}
        },
        "should": [
            { "match": {"tag": "starred" } },
            { "range": { "date": {"gte": "2014-01-01"} } }
        ]
    }
}

** 查询与过滤条件的合并


1 带过滤的查询语句 , filtered 来同时包含 "query" 和 "filter" 子句
{
    "filtered": {
        "query": {
            "match": { "email": "business opportunity" }
        },
        "filter": {
            "term": { "folder": "inbox" }
        }
    }
}


{
    "filtered": {
        "query": { "match_all": {}}, -- 查询语句可以省略 相当于 match all
        "filter": {
            "term": { "folder": "inbox" }
        }
    }
}

-------------------------------排序--------------------------------


GET /_search
{
    "query": {
        "filtered": {
            "filter": {
                "term": {"user_id": 1 }
            }
        }
    },
    "sort": {
        "date": { "order": "desc" }
    }
}


_score


多级排序
"sort": [
   { "date":   { "order": "desc" }},
   { "_score": { "order": "desc" }}
]



被分析器(analyser)处理过的字符称为 analyzed field (译者注:即已被分词并排序的字段,所有写入ES中的字段默认圴会被analyzed),
analyzed 字符串字段同时也是多值字段,在这些字段上排序往往得不到你想要的值。
比如你分析一个字符"fine old art",它最终会得到三个值。
例如我们想要按照第一个词首字母排序,如果第一个单词相同的话,再用第二个词的首字母排序,以此类推,
可惜ElasticSearch在进行排序时是得不到这些信息的。




**********
相关性
ElasticSearch的相似度算法被定义为 TF/IDF,即检索词频率/反向文档频率


检索词频率
检索词在该字段出现的频率,出现频率越高,相关性也越高。
反向文档频率
检索词在索引中出现的频率,频率越高,相关性越低。
检索词出现在多数文档中会比出现在少数文档中的权重更低

------------------------索引管理---------------------------

1 创建索引 
简单的通过添加一个文档的方式创建了一个索引。这个索引使用默认设置,新的属性通过动态映射添加到分类中。
现在我们需要对这个过程有更多的控制:我们需要确保索引被创建在适当数量的分片上,在索引数据之前设置好分析器和类型映射。

禁止自动创建索引:
 - config/elasticsearch.yml
 - action.auto_create_index : false


2 删除索引

3 索引设置
number_of_shards
定义一个索引的主分片个数,默认值是 5 。这个配置在索引创建后不能修改。


number_of_replicas
每个主分片的复制分片个数,默认是 1 。这个配置可以随时在活跃的索引上修改。

4 配置分析器

standard 分析器 : 大部分西方语系
whitespace :
simple :
english :

"name": {
   "type": "string",
   "analyzer": "whitespace"
}

不同类型的文档可以被加到同一个索引里

*********动态映射


dynamic  true   自动添加字段(默认)
         false  忽略字段
         strict  当遇到未知字段时抛出异常


{
    "mappings": {
        "my_type": {
            "dynamic": "strict", -- 当遇到未知字段时, my_type 对象将会抛出异常
             "properties": {
                "title": {
                    "type": "string"
                },
                "stash": {
                    "type": "object",
                    "dynamic": true -- stash 对象会自动创建字段
                }
            }
        }
    }
}


自定义动态映射


动态模板 ****
    使用 dynamic_templates ,你可以完全控制新字段的映射,你设置可以通过字段名或数据类型应用一个完全不同的映射。

例子


{
    "mappings": {
        "my_type": {
            "dynamic_templates": [
                {
                    "es": {  -- 名称
                        "match": "*_es",   -- 字段名以 _es 结尾需要使用 spanish 分析器
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "string",
                            "analyzer": "spanish"
                        }
                    }
                },
                {
                    "en": {
                        "match": "*",  -- 所有其他字段使用 english 分析器。 匹配所有字符串类型字段
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "string",
                            "analyzer": "english"
                        }
                    }
                }
            ]
        }
    }
}


match_mapping_type  :允许你限制模板只能使用在特定的类型上 (例如 strong 和 long )

match       :只匹配字段名, 
path_match  :匹配字段在一个对象中的完整路径

_default_ 默认映射


{
    "mappings": {
        "_default_": {
            "_all": { "enabled": false }  -- 映射对所有类型禁用 _all 字段
        },
        "blog": {
            "_all": { "enabled": true }    -- 只在 blog 字段上开启 _all 字段
        }
    }
}



_default_ 映射也是定义索引级别的动态模板的好地方

重建索引


可以给索引添加新的类型,或给类型添加新的字段,但是你不能添加新的分析器或修改已有字段
但是可以通过重建索引来完成

---重点查询中的聚合
统计每种兴趣下职员的平均年龄


GET /megacorp/employee/_search


{
    "aggs": {
        "all_interests": {
            "terms": {
                "field": "interests"
            },
            "aggs": {
                "avg_age": {
                    "avg": {
                        "field": "age"
                    }
                }
            }
        }
    }
}


基于短语(Term-based)的查询
全文(Full-text)检索

----------了解部分--------------------


文档到分片


shard = hash(routing) % number_of_primary_shards


routing 一般是 _id 字段


主分片的数量只能在创建索引时定义且不能修改,如果主分片的数量在未
来改变了,所有先前的路由值就失效了,文档也就永远找不到了。


主分片  复制分片


master 请求节点


文档能够从主分片或任意一个复制分片被检索。

-------------分布式搜索-----了解即可-
查询阶段  
取回阶段 



管理命令

查看索引
curl 192.168.1.201:9200/_cat/indices?v

删除索引


curl  -XDELETE '192.168.1.201:9200/razor_cd'


curl  -XDELETE '192.168.1.201:9200/razor_event'


curl  -XDELETE '192.168.1.201:9200/razor_usinglog'


curl  -XDELETE '192.168.1.201:9200/razor_app'


curl  -XDELETE '192.168.1.201:9200/razor_tag'

curl  -XGET '192.168.1.201:9200/razor_cd/clientdata/_search?pretty=true'


curl  -XGET '192.168.1.201:9200/razor_app/app_info/_search?pretty=true'


curl  -XGET '192.168.1.201:9200/razor_tag/app_tag/_search?pretty=true'


curl  -XGET '192.168.1.201:9200/razor_event/event/_search?pretty=true'


curl  -XGET '192.168.1.201:9200/razor_usinglog/usinglog/_search?pretty=true'

curl  -XGET '192.168.1.201:9200/razor_app/app_info/_search?pretty=true' -d '
{
    "query": {
        "range": {
            "localtime": {
                "gte": "2016-03-28 00:00:00",
                "lt": "2016-03-28 10:08:00"
            }
        }
    }
}'


curl  -XGET '192.168.1.201:9200/razor_app/app_info/_search?pretty=true' -d '
{
    "query": {
        "match": {
            "user_id": "0c5ead1ca4bda378f0784440eda92700"
        }
    }
}'

curl  -XGET '192.168.1.201:9200/razor_cd/clientdata/_search?pretty=true' -d '
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user_id": "a8013699209"
          }
        },
        {
          "match": {
            "product_id": "10028147"
          }
        }
      ]
    }
  },
  "sort": {
    "localtime": {
      "order": "desc"
    }
  },
  "from": 0,
  "size": 100
}
'





你可能感兴趣的:(大数据)