基础篇
一.分片
分片是一个功能完整的搜索引擎,它拥有使用一个节点上的所有资源的能力。 索引一旦创建分片数量就已经确定,且不可更改,默认为5个分片,每个分片有1个副本
二.文档元数据;
_index:
索引名,这个名字必须小写,不能以下划线开头,不能包含逗号
_type:
索引下的逻辑分区
一个 _type 命名可以是大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号, 并且长度限制为256个字符
_id:
_id+ _index + _type 组合确定ES中的一个文档
三:更新和冲突
1 为了避免数据丢失, update API 在 检索 步骤时检索得到文档当前的 _version 号,并传递版本号到 重建索引 步骤的 index 请求。 如果另一个进程修改了处于检索和重新索引步骤之间的文档,那么 _version 号将不匹配,更新请求将会失败。
2 这可以通过设置参数 retry_on_conflict 来自动完成, 这个参数规定了失败之前 update 应该重试的次数,它的默认值为 0 。
POST /website/pageviews/1/_update?retry_on_conflict=5
四:查询
1:空搜索:
GET /_search 返回集群中所有索引下的所有文档
2:/_search
在所有的索引中搜索所有的类型
/gb/_search
在 gb 索引中搜索所有的类型
/gb,us/_search
在 gb 和 us 索引中搜索所有的文档
/g*,u*/_search
在任何以 g 或者 u 开头的索引中搜索所有的类型
/gb/user/_search
在 gb 索引中搜索 user 类型
/gb,us/user,tweet/_search
在 gb 和 us 索引中搜索 user 和 tweet 类型
/_all/user,tweet/_search
在所有的索引中搜索 user 和 tweet 类型
3:分页
size
显示应该返回的结果数量,默认是 10
from
显示应该跳过的初始结果数量,默认是 0
在分布式系统中深度分页:
1>现在假设我们请求第 1000 页— 结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。
可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。
4:_all字段
1)当索引一个文档的时候,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引 _all字段:String类型
2)除非设置特定字段,否则查询字符串就使用 _all 字段进行搜索。
五:分词
1)分词过程
字符过滤器
首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and。
分词器
其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
Token 过滤器
最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 a, and, the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。
2)测试分词分析
GET /_analyze
{
“analyzer”: “standard”,
“text”: “Text to analyze”
}
六:映射
1)Elasticsearch 支持如下简单域类型:
- 字符串:
- ElasticSearch 5.0以后,string类型有重大变更,移除了string类型,string字段被拆分成两种新的数据类型: text用于全文搜索的,而keyword用于关键词搜索。ElasticSearch字符串将默认被同时映射成text和keyword类型,将会自动创建下面的动态映射(dynamic mappings)
• {
“foo”: {
“type”: “text”,
“fields”: {
“keyword”: {
“type”: “keyword”,
“ignore_above”: 256
}
}
}
}
- 整数 : byte, short, integer, long
- 浮点数: float, double
- 布尔型: boolean
- 日期: date 查询映射:GET /index/_mapping/type ES7去除了type 类型一旦指定,不可更改,可以增加 2)自定义域映射:
• {
“tag”: {
“type”: “string”, //类型
“index”: “analyzed” ,
“analyzer:”english”
}
}
- index 属性控制怎样索引字符串,可选三个值
analyzed
首先分析字符串,然后索引它。换句话说,以全文索引这个域。
not_analyzed
索引这个域,所以它能够被搜索,但索引的是精确值。不会对它进行分析。
no
不索引这个域。这个域不会被搜索到。
其他简单类型(例如 long , double , date 等)也接受 index 参数,但有意义的值只有 no 和 not_analyzed , 因为它们永远不会被分析。 - analyzer
对于 analyzed 字符串域,用 analyzer 属性指定在搜索和索引时使用的分析器。默认, Elasticsearch 使用 standard 分析器, 但你可以指定一个内置的分析器替代它,例如 whitespace 、 simple 和 english:
2)复杂核心域类型 - 多值域:如果你通过索引数组来创建新的域,Elasticsearch 会用数组中第一个值的数据类型作为这个域的 类型 。
- 空域:null,[]等
- 多层级对象与内部对象的映射:Lucene 不理解内部对象。 Lucene 文档是由一组键值对列表组成的
七、查询表达式
典型结构:
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,…
}
}
针对某个字段:
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,…
}
}
}
1)分类:
- 叶子语句(Leaf clauses) (就像 match 语句) 被用于将查询字符串和一个字段(或者多个字段)对比。
- 复合(Compound) 语句 主要用于 合并其它查询语句。 比如,一个 bool 语句 允许在你需要的时候组合其它语句,无论是 must 匹配、 must_not 匹配还是 should 匹配,同时它可以包含不评分的过滤器(filters)
2)过滤查询(filter)与评分查询(query): - 过滤(filtering)的目标是减少那些需要通过评分查询(scoring queries)进行检查的文档。
- 通常的规则是,使用查询(query)语句来进行 全文 搜索或者其它任何需要影响 相关性得分 的搜索。除此以外的情况都使用过滤(filters)。
3)最重要的查询 - match_all
- match(标准查询):
- 如果你在一个全文字段上使用 match 查询,在执行查询前,它将用正确的分析器去分析查询字符串
- 如果在一个精确值的字段上使用它,例如数字、日期、布尔或者一个 not_analyzed 字符串字段,那么它将会精确匹配给定的值
- 格式:{“match”:{字段名:字段值}}
- 返回部分数据:
• GET /_search
{
“query”: { “match_all”: {}},
“_source”: [ “title”, “created” ]
}
- multi_match
• {
“multi_match”: {
“query”: “full text search”,
“fields”: [ “title”, “body” ]
}
}
- Range::查询落在指定区间内的时间或数字
• {
“range”: {
“age”: {
“gte”: 20,
“lt”: 30
}
}
}
- term查询: term 查询被用于精确值匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed 的字符串:
• 格式:{
“Term”:{
“字段名”:”字段值“
}
}
- terms查询: terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件
• 格式:{
“terms”:{
“字段名”:[”字段值1“,”字段值2”]
}
}
- exists 查询和 missing 查询 用户查询指定的字段有值或者没有值的情况 格式:
• {
“exists”: {
“field”: “字段名”
}
}
4)组合多查询
must
文档 必须 匹配这些条件才能被包含进来。
must_not
文档 必须不 匹配这些条件才能被包含进来。
should
如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。
filter
必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。
{
“bool”: {
“must”: { “match”: { “title”: “how to make millions” }},
“must_not”: { “match”: { “tag”: “spam” }},
“should”: [
{ “match”: { “tag”: “starred” }},
{ “range”: { “date”: { “gte”: “2014-01-01” }}}
]
}
}
如果没有 must 语句,那么至少需要能够匹配其中的一条 should 语句。但,如果存在至少一条 must 语句,则对 should 语句的匹配没有要求。
五)验证查询
GET /gb/tweet/_validate/query?explain
{
“query”: {
“tweet” : {
“match” : “really powerful”
}
}
}
八:排序
1:排序规则
默认按照_score字段排序,可以指定排序的字段
- 单字段排序:
• “sort”:{
“字段名”:“desc”
}
- 多级排序:
• “sort”:[
{“字段名”:desc}…
]
- 多值字段的排序:
• “sort”: {
“dates”: {
“order”: “asc”,
“mode”: “min”
}
}
2: 相关性的计算规则
检索词频率
检索词在该字段出现的频率?出现频率越高,相关性也越高。 字段中出现过 5 次要比只出现过 1 次的相关性高。
反向文档频率
每个检索词在索引中出现的频率?频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。
字段长度准则
字段的长度是多少?长度越长,相关性越低。 检索词出现在一个短的 title 要比同样的词出现在一个长的 content 字段权重更大。
链接:
(152条消息) TF-IDF(词频-逆文档频率)介绍_逆文档频率为什么要用对数_北京小辉的博客-CSDN博客
原理篇
一:执行分布式检索
查询阶段
- 客户端发送一个 search 请求到 Node 3 , Node 3 会创建一个大小为 from + size 的空优先队列。
- Node 3 将查询请求转发到索引的每个主分片或副本分片(轮训发送)中。每个分片在本地执行查询并添加结果到大小为 from + size 的本地有序优先队列中。
- 每个分片返回各自优先队列中所有文档的 ID 和排序值(比如_score)给协调节点,也就是 Node 3 ,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
取回阶段 - 协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。
- 每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。
- 一旦所有的文档都被取回了,协调节点返回结果给客户端。
备注:深度分页
- 先查后取的过程支持用 from 和 size 参数分页,但是这是 有限制的 。 要记住需要传递信息给协调节点的每个分片必须先创建一个 from + size 长度的队列,协调节点需要根据 number_of_shards * (from + size) 排序文档,来找到被包含在 size 里的文档。
- 但是使用足够大的 from 值,排序过程可能会变得非常沉重,使用大量的CPU、内存和带宽。因为这个原因,我们强烈建议你不要使用深分页
搜索选项 - 偏好preference
bouncing results 问题: 每次用户刷新页面,搜索结果表现是不同的顺序。 让同一个用户始终使用同一个分片,这样可以避免这种问题, 可以设置 preference 参数为一个特定的任意值比如用户会话ID来解决
选项设置:
Preference | Elasticsearch Reference [5.6] | Elastic - 超时问题
Timeout告诉 分片允许处理数据的最大时间
游标查询:
- scroll 查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
- 游标查询允许我们 先做查询初始化,然后再批量地拉取结果,会取某个时间点的快照数据
- 深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。 游标查询用字段 _doc 来排序
游标查询 Scroll | Elasticsearch: 权威指南 | Elastic
注释:_doc 其实就是按照Lucene 文件结构的当时索引时的先后顺序,那么按道理它就是最快的,_doc值能把保证在每个分片是唯一的,但是不能保证全局唯一
二.索引管理
1)索引设置
- number_of_shards
每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。 - number_of_replicas
每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改 - 创建时设置:
• PUT /my_temp_index
{
“settings”: {
“number_of_shards” : 1,
“number_of_replicas” : 0
}
}
- 创建后修改副本数:
PUT /my_temp_index/_settings
{
“number_of_replicas”: 1
}
2)类型和映射- Lucene 没有文档类型的概念,每个文档的类型名被存储在一个叫 _type 的元数据字段上。 当我们要检索某个类型的文档时, Elasticsearch 通过在 _type 字段上使用过滤器限制只返回这个类型的文档。
- 每个 Lucene 索引中的所有字段都包含一个单一的、扁平的模式。一个特定字段可以映射成 string 类型也可以是 number 类型,但是不能两者兼具(不同的类型在一个索引上)。因为类型是 Elasticsearch 添加的 优于 Lucene 的额外机制(以元数据 _type 字段的形式),在 Elasticsearch 中的所有类型最终都共享相同的映射。
- 所以高版本中移除了类型的概念
3)动态映射
1)动态映射设置
true
动态添加新的字段— 缺省
false
忽略新的字段,新的字段不会被加到映射中也不可搜索
strict
如果遇到新字段抛出异常
如: - PUT /my_index
• {
“mappings”: {
“my_type”: {
• “dynamic”: “strict”,
“properties”: {
“title”: { “type”: “string”},
“stash”: {
“type”: “object”,• “dynamic”: true
}
}
}
}
}
- 配置参数 dynamic 可以用在根 object 或任何 object 类型的字段上
如果遇到新字段,对象 my_type 就会抛出异常。 而内部对象 stash 遇到新字段就会动态创建新字段。
2)自定义动态映射
- 日期检测
默认检测格式:yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z
修改日期检测格式(需在创建索引时指定):
修改映射格式 或者在创建映射时指定:
• “create_date” : {
“type” : “date”,
“format” : “MM/dd/yyyy”
}
- 3)重新索引数据重新索引数据