怎样给公司做网站,外国老头做中文网站,杭州网站制作方法,现在可以用的网站本文已收录至Github#xff0c;推荐阅读 #x1f449; Java随想录 微信公众号#xff1a;Java随想录 文章目录 查询上下文相关度评分#xff1a;scoreTF/IDF BM25 源数据#xff1a;source 源数据过滤全文检索match#xff1a;匹配包含某个term的子句match_all推荐阅读 Java随想录 微信公众号Java随想录 文章目录 查询上下文相关度评分scoreTF/IDF BM25 源数据source 源数据过滤全文检索match匹配包含某个term的子句match_all匹配所有结果的子句multi_match多字段条件match_phrase短语查询 Term Queryterm匹配和搜索词项完全相等的结果term和match_phrase的区别 terms匹配和搜索词项列表中任意项匹配的结果 Range范围查找FilterFilter缓存机制 Bool Queryshould与must或filter一起使用minimum_should_match DSL是Domain Specific Language的缩写指的是为特定问题领域设计的计算机语言。这种语言专注于某特定领域的问题解决因而比通用编程语言更有效率。 在Elasticsearch中DSL指的是Elasticsearch Query DSL是一种以JSON形式表示的查询语言。通过这种语言用户可以构建复杂的查询、排序和过滤数据等操作。这些查询可以是全文搜索、聚合搜索也可以是结构化的搜索。
查询上下文
搜索是Elasticsearch中最关键和重要的部分使用query关键字进行检索更倾向于相关度搜索故需要计算评分。
在查询上下文中一个查询语句表示一个文档和查询语句的匹配程度。无论文档匹配与否查询语句总能计算出一个相关性分数在_score字段上。
相关度评分score
相关度评分用于对搜索结果排序评分越高则认为其结果和搜索的预期值相关度越高即越符合搜索预期值默认情况下评分越高则结果越靠前。在7.x之前相关度评分默认使用TF/IDF算法计算而来7.x之后默认为BM25。
score是根据各种因素计算出来的包括
Term Frequency词频一个词在文档中出现的次数越多score就越高。Inverse Document Frequency逆文档频率一个词在所有文档中出现的次数越少score就越高。Field Length Norm字段长度规范字段的长度越短score就越高。
这三个因素共同决定了score的值。然而你也可以通过设置自定义评分或者禁用评分来影响score的计算。
TF/IDF BM25
TF/IDF是一种在信息检索和文本挖掘中广泛使用的统计方法用于评估一个词语对于一个文件集或一个语料库中的一个文件的重要程度。名称中的TF表示“术语频率”IDF表示“逆向文件频率”。
TF (Term Frequency) 这是衡量词在文档中出现的频率。通常来说一个词在文档中出现的次数越多其重要性就可能越大。但这并不总是正确的比如在很多英文文档中“the”、“and”等词出现的频率非常高但我们并不能因此认为它们就非常重要。因此需要结合 IDF 来使用。IDF (Inverse Document Frequency) 这是衡量词是否常见的度量。如果某个词在许多文档中都出现那么它可能并不具有区分性对于搜索和分类的帮助就不大。例如每篇英文文章中都会出现的“the”对于区分文章内容就没有什么帮助。所以如果一个词在所有文档中出现得越多那么其 IDF 值就会越小相反如果一个词很少在文档中出现那么其 IDF 值就会较大。
TF-IDF 会将这两个因子结合起来为每个词产生一个权重。具有较高 TF-IDF 分数的词被认为在文档中更重要。通过这种方式ES 能够提供相关性排序使得包含用户查询词汇的最相关文档排在搜索结果的前面。
BM25是一种更先进的排名函数也是基于TF/IDF的一种改进型方法。它引入了两个新概念:
文档长度归一化长文档可能会有更多的关键词但这并不意味着它与查询更相关。BM25通过调整文档长度来解决这个问题。饱和度在TF/IDF中词项的出现频率越高其重要性就越大。然而在实践中一旦一个词在文档中出现过再次出现时增加的相关性可能会降低。BM25通过设置一个饱和点来解决这个问题超过这个点词的权重增加就会变得不那么敏感。
总结而言BM25是TF/IDF的改进版通过文档长度归一化和频率饱和度控制来优化搜索结果。
源数据source
_source字段包含索引时原始的JSON文档内容字段本身不建立索引因此无法进行搜索但是会被存储所以当执行获取请求是可以返回_source字段。
虽然很方便但是_source字段的确会对索引产生存储开销你可以通过关闭_source字段来节省空间但这通常不建议因为有了原始数据我们可以对数据进行重新索引并且在获取数据时也更加灵活。
如果你禁用了_source字段那么会有以下几个影响
无法获取原始数据当你查询某个文档时你将无法获取到原始的_source字段内容因为它没有被存储在Elasticsearch中。更新和重新索引的问题如果你想更新文档或者执行重新索引操作可能会遇到问题因为这两种操作都需要原始的_source字段。脚本字段和某些Aggregations可能受到影响如果你正在使用脚本字段或者依赖_source字段的Aggregations那么禁用_source可能导致这些特性出问题。
下面是一些使用_source字段的例子
在索引文档时启用/禁用_source
PUT my_index
{mappings: {_source: {enabled: false},properties: {field1: { type: text }}}
}在这个例子中新创建的my_index索引将不会存储_source字段。
获取文档的_source字段
GET /my_index/_doc/1返回的结果中会包含_source字段。
在获取文档时只获取_source字段中特定的字段
GET /my_index/_doc/1?_sourcefield1,field2在这个例子中返回的_source字段只包含field1和field2。
注意_source字段并不用于搜索禁用_source字段不会影响你的搜索结果。
源数据过滤
假设你的应用只需要获取部分字段如name和price而其他字段如desc和tags不经常使用或者数据量较大导致传输和处理这些额外的数据会增加网络开销和处理时间。在这种情况下通过设置includes和excludes可以有效地减少每次请求返回的数据量提高效率。
例如
PUT product
{mappings: {_source: {includes: [name, price],excludes: [desc, tags]}}
}Including结果中返回哪些field。
Excluding结果中不要返回哪些fieldExcluding优先级比Including更高。 需要注意的是尽管这些设置会影响搜索结果中_source字段的内容但并不会改变实际存储在Elasticsearch中的数据。也就是说desc和tags字段仍然会被索引和存储只是在获取源数据时不会被返回。 上述这种在mapping中定义的方式不推荐因为mapping不可变。我们可以在查询过程中指定返回的字段如下
GET product/_search
{_source: {includes: [owner.*, name],excludes: [name, desc, price]},query: {match_all: {}}
}Elasticsearch的_source字段在查询时支持使用通配符wildcards来包含或排除特定字段。使得能够更灵活地操纵返回的数据。
关于规则可以参考以下几点:
*匹配任意字符序列包括空序列。?匹配任意单个字符。[abc] 匹配方括号内列出的任意单个字符。例如[abc]将匹配a, “b”, 或 “c”。
请注意通配符表达式可能会导致查询性能下降特别是在大型索引中因此应谨慎使用。
全文检索
全文检索是Elasticsearch的核心功能之一它可以高效地在大量文本数据中寻找特定关键词。
在Elasticsearch中全文检索主要依靠两个步骤“分析”Analysis和查询Search。
分析 当你向Elasticsearch插入一个文档时会进行分析处理将原始文本数据转换成称为tokens或terms的小片段。这个过程可能包括如下操作 切分文本Tokenization将所有字符转换为小写Lowercasing删除常见但无重要含义的单词Stopwords提取词根Stemming 查询当执行全文搜索时查询字符串也会经过类似的分析过程然后再与已经分析过的数据进行比对找出匹配的结果并返回。
Elasticsearch提供了许多种全文搜索的查询类型例如
Match Query最基本的全文搜索查询。Match Phrase Query用于查找包含特定短语的文档。Multi-Match Query类似Match Query但可以在多个字段上进行搜索。Query String Query提供了丰富的搜索语法可以执行复杂的、灵活的全文搜索。
match匹配包含某个term的子句
match 查询是 Elasticsearch 中的一种全文查询方式它包括标准分析和词项搜索。尽管它可以应用于精确字段但其主要用途是进行全文搜索。当与全文字段一起使用时match 查询可以解析查询字符串并执行短语查询或者构建一个布尔查询这意味着它会考虑字段中的每个单词。
下面有一个简单的 match 查询示例
GET /_search
{query: {match: {message: this is a test}}
}在这个示例中Elasticsearch 会在 “message” 字段中搜索包含 “this”、“is”、“a” 和 “test” 的文档。
请注意match 查询不仅仅会匹配完全相同的短语它还可以处理更复杂的情况如多个单词它会匹配任何一个、误拼、同义词等这主要取决于你所使用的分析器和搜索设置。
match 查询还有一些其他参数例如
operator定义多个搜索词之间的关系默认为 or。如果设为 and则返回的文档必须包含所有搜索词。minimum_should_match控制返回的文档应至少匹配的搜索词的数量或比例。fuzziness允许模糊匹配可以找到那些拼写错误或接近的词汇。
match_all匹配所有结果的子句
match_all是Elasticsearch中的一个查询类型用于获取索引中的所有文档。
这是一个match_all查询的基本示例
{query: {match_all: {}}
}在上述示例中我们可以看到查询对象中存在一个match_all字段其值是一个空对象。这表示我们希望匹配所有文档。
需要注意由于 match_all 查询可能返回大量的数据所以一般在使用时都会与分页pagination功能结合起来这样可以控制返回结果的数量避免一次性加载过多数据导致的性能问题。例如你可以使用 from 和 size 参数来限制返回结果
GET /_search
{query: {match_all: {}},from: 10,size: 10
}Elasticsearch的 match_all 查询是最简单的查询它不需要任何参数但如果你想为它添加权重可以使用 boost 参数。例如
GET /_search
{query: {match_all: { boost : 1.2 }}
}在上面的查询中boost 参数被设置为1.2给匹配到的所有文档增加了额外的相关性得分提升。
multi_match多字段条件
multi_match 可以用来在多个字段上进行全文搜索。它接受一个查询字符串和一组需要在其中执行查询的字段列表。
例如
{query: {multi_match : {query: 这是测试, fields: [ field1, field2 ] }}
}在此示例中查询字符串这是测试将在字段field1和field2中搜索。
multi_match查询也支持使用通配符(*)来匹配多个字段
{query: {multi_match : {query: 这是测试, fields: [ *_name ] }}
}在这个例子中会在所有以_name结尾的字段中进行搜索。
此外multi_match 查询还支持许多参数包括
type设置查询类型可选值包括best_fields, most_fields, cross_fields, phrase, phrase_prefix 等。
例如“best_fields” 类型会从指定的字段中挑选分数最高的匹配结果计算最终得分而“most_fields” 类型则会在每个字段中都寻找匹配项并将其分数累加起来。
tie_breaker当一个词在多个字段中找到时用于决定最终得分的参数。minimum_should_match用于控制应匹配的最小子句数。operator主要有两个操作符 OR 和 AND默认为 OR。
需要注意的是当使用 multi_match 查询时如果字段不同其权重可能也会不同。你可以通过在字段名后面添加尖括号^和权重值来调整特定字段的权重。例如fields: [ name^3, description ]表示在name字段中的匹配结果权重是description字段的三倍。
match_phrase短语查询
match_phrase 用于精确匹配包含指定短语的文档。match_phrase 查询需要字段值中的单词顺序与查询字符串中的单词顺序完全一致。
例如
GET /_search
{query: {match_phrase: {message: this is a test}}
}这个查询将会找到message字段中包含完整短语this is a test的所有文档。
此外match_phrase 查询还有一个 slop 参数可以定义词组中的词语可能存在的位置偏移量。例如如果将 slop 设置为 1则查询 “this is a test” 也可匹配 “this is test a”因为 “a” 和 “test” 只需移动一个位置即可匹配。
GET /_search
{query: {match_phrase: {query: this is a test,slop: 2}}
}请注意match_phrase 查询需要整个短语完全匹配而不仅仅是查询中的所有单词都存在。如果你只是希望所有单词都存在而不关心它们的顺序或精确出现方式那么你应该使用 match 查询。
Term Query
精确查询用于查找包含指定精确值的文档而不是执行全文搜索。
term匹配和搜索词项完全相等的结果
term 查询主要用于查询某个字段完全匹配给定值的文档。这对精确匹配非常有效例如数字、布尔值或者字符串。
用法示例
GET /_search
{query: {term : { user : Kimchy } }
}在这个例子中我们正在搜索user字段中完全匹配Kimchy的文档。
需要注意的是term 查询对于分析过的字段例如文本字段可能不会像你预期的那样工作因为它会搜索精确的词汇项而不是单词。如果你想要对文本字段进行全文搜素应该使用 match 查询。
另外一个需要注意的点就是 term 查询对大小写敏感所以 “Kimchy” 和 “kimchy” 是两个不同的词条。
term和match_phrase的区别
term 查询和 match_phrase 查询是 Elasticsearch 提供的两种查询方式它们都用于查找文档但主要的区别在于如何解析查询字符串以及匹配的精确度。
term这个查询做的是精确匹配。当你使用term查询时Elasticsearch会查找完全等于你指定的词汇的文档。例如如果你搜索term “apple”那么只有包含完全为apple的文档会被匹配到而包含apples或APPLE的文档则不会被匹配到。因此term查询对大小写敏感且不会进行任何形式的分析如停用词移除、词干提取等。match_phrase这个查询是用来匹配一系列词汇或者短语的。match_phrase查询会保证你查询的词汇必须以你提供的顺序完全匹配。比如如果你使用match_phrase查询 “quick brown fox”那么只有包含这个完整短语的文档才会被匹配到单独包含quick、brown或者fox的文档则不会被匹配到。此外与term查询不同match_phrase查询会进行文本分析这意味着它会考虑词汇的大小写、复数形式等。
总结来说term查询更适合精确匹配而match_phrase查询更适合短语匹配。但是match_phrase并不能100%保证精确匹配因为它会处理和考虑文本的各种变体比如大小写、单复数形式等。
terms匹配和搜索词项列表中任意项匹配的结果
terms 查询用于匹配指定字段中包含一个或多个值的文档。这是一个精确匹配查询不会像全文查询那样对查询字符串进行分析。
假设你有一个 “user” 的字段并且你想找到该字段值为 “John” 或者 “Jane” 的所有文档你可以使用 terms 查询
GET /_search
{query: {terms : {user : [John, Jane],boost : 1.0}}
}上面的查询将返回所有user 字段等于 “John” 或者 “Jane” 的文档。
其中boost 参数用于增加或减少特定查询的相对权重。它将改变查询结果的相关性分数_score以影响最终结果的排名。
例如在上述 terms 查询中boost 参数被设置为 1.0。这意味着如果字段 “user” 的值包含 “John” 或 “Jane”那么其相关性分数_score就会乘以 1.0。因此这个设置实际上并没有改变任何东西因为乘以 1 不会改变原始分数。但是如果你将 boost 参数设置为大于 1 的数那么匹配的文档的 _score 将会提高反之则会降低。
Range范围查找
Range查询允许我们查找某个范围内的值。假设我们有一个商品表其中有商品价格字段我们可以用range查询来查找价格在一定范围内的商品。
以下是一个基础的范围查询的例子
GET /products/_search
{query: {range : {price : {gte : 10,lte : 20,boost : 2.0}}}
}在这个例子中我们正在查询价格大于或等于gte10且小于或等于lte20的所有商品。boost参数表示增加该查询的重要性。
Range查询支持以下参数
gte大于或等于。lte小于或等于。gt大于。lt小于。boost增加查询的重要性。
此外对于日期类型的字段你还可以使用如下方式进行范围查询
{query: {range : {timestamp : {gte : now-1d/d,lt : now/d}}}
}在上述查询中我们正在查找过去24小时内的数据。now-1d/d表示从现在算起的一天前而now/d表示当前时间。
Filter
过滤器Filter是用于筛选数据的一种工具。过滤器和查询query相似但有几个重要的区别
过滤不关心文档的相关度得分relevance score查询会为每个匹配的文档计算一个相关度得分以决定返回结果的排序。相比之下过滤器只关心文档是否匹配 - 没有“部分匹配”只有“匹配”或“不匹配”。过滤器可以被缓存由于过滤器不需要计算得分因此它们的结果可以被缓存起来用于之后的搜索请求这可以大大提高性能。
常见的过滤器类型包括term、terms、range、bool、match_all 等。例如范围过滤器 range 可以用于查找数字或日期字段在指定范围内的文档布尔过滤器 bool 则允许你组合多个过滤器并定义它们如何互相交互。
使用过滤器时通常会把它们放在 bool 查询的 filter 子句中。例如
{query: {bool: {filter: [{ term: { status: active }},{ range: { age: { gte: 30, lte: 40 }}}]}}
}这个查询会返回所有“状态为 active 并且年龄在 30 到 40 之间”的文档而不会考虑它们的相关度得分。
Filter缓存机制
在 Elasticsearch 中过滤查询结果的缓存机制是非常重要的一个性能优化手段。由于过滤器filter只关心是否匹配而不关心评分 (_score)因此它们的结果可以被缓存以提高性能。
每次 filter 查询执行时Elasticsearch 都会生成一个名为 “bitset” 的数据结构其中每个文档都对应一个位0 或 1表示这个文档是否与 filter 匹配。这个 bitset 就是被存储在缓存中的部分。
如果相同的 filter 查询再次执行Elasticsearch 可以直接从缓存中获取这个 bitset而不需要再次遍历所有的文档来找出哪些文档符合这个 filter。这大大提高了查询速度并减少了 CPU 使用。
这种缓存策略特别适合那些重复查询的场景例如用户界面的过滤器和类似的功能因为他们通常会产生很多相同的 filter 查询。
然而值得注意的是虽然这种缓存可以显著改善查询性能但也会占用内存空间。如果你有很多唯一的过滤条件那么过滤器缓存可能会变得很大从而导致内存问题。这就需要你对使用的过滤器进行适当的管理和限制。
Filter缓存功能会遵循以下原则
同一Filter的多次应用如果在后续查询中有多次使用相同的Filter则ES会把第一次查询的结果储存在缓存中后续的查询将直接从缓存中获取结果而不再做任何磁盘I/O或者其他计算。根据需求清理缓存ES会根据内存使用情况自动清理缓存当然你也可以手动清空缓存。但这并不意味着我们无限制地依赖Filter缓存大量的缓存可能导致更重的GC压力。不缓存复杂查询一些查询条件较复杂的过滤器可能不会被缓存比如script filter、geo filter等。这是因为这些过滤器本身的构建和维护成本可能就超过了查询的计算成本。
ES的Filter缓存机制可以大大提高查询效率但如果不慎用比如缓存过多或者不适合缓存的查询可能会对性能产生负面影响。因此在设计和优化ES查询时应当充分考虑Filter的使用和缓存策略。
Bool Query
Bool Query组合查询可以组合多个查询条件bool查询也是采用more_matches_is_better的机制因此满足must和should子句的文档将会合并起来计算分值。 boost和minumum_should_match是参数其他四个都是查询子句。
must必须满足子句查询必须出现在匹配的文档中并将有助于得分。filter过滤器不计算相关度分数。should满足 or子句查询应出现在匹配的文档中。must_not必须不满足不计算相关度分数 not子句查询不得出现在匹配的文档中。子句在过滤器上下文中执行这意味着计分被忽略并且子句被视为用于缓存。
例子1下面的语句表示包含xiaomi或phone 并且包含shouji的文档例子
GET product/_search
{query: {bool: {must: [{match: {name: xiaomi phone}},{match_phrase: {desc: shouji}}]}}
}should与must或filter一起使用
当 should 子句与 must 或 filter 子句一起使用时这时候需要注意了。
只要满足了 must 或 filter 的条件should 子句就不再是必须的。换句话说如果存在一个或者多个 must 或 filter 子句那么 should 子句的条件会被视为可选。
然而如果 should 子句与 must_not 子句单独使用也就是没有 must 或 filter则至少需要满足一个 should 子句的条件。
这里有一个例子来说明
GET /_search
{query: {bool: {must: [{ term: { user: kimchy }}],filter: [{ term: { tag: tech }}],should: [{ term: { tag: wow }},{ term: { tag: elasticsearch }}]}}
}在这个查询中must 和 filter 子句的条件是必须满足的而 should 子句的条件则是可选的。如果匹配的文档同时满足 should 子句的条件那么它们的得分将会更高。
那如果我们一起使用的时候想让should满足该怎么办这时候minimum_should_match 参数就派上用场了。
minimum_should_match
minimum_should_match参数定义了在 should 子句中至少需要满足多少条件。
例如如果你有5个 should 子句并且设置了 minimum_should_match: 3那么任何匹配至少三个 should 子句的文档都会被返回。
这个参数可以接收绝对数值如 2、百分比如 30%、和组合如 390% 表示至少匹配3个或者90%取其中较大的那个等不同类型的值。
注意如果 bool 查询中只有 should 子句没有 must 或 filter那么默认情况下至少需要匹配一个 should 条件也就是minimum_should_match默认值是1除非 minimum_should_match 明确设定为其他值。如果包含 must 或 filter的情况下minimum_should_match默认值 0。
所以我们可以在包含must 或 filter的情况下设置minimum_should_match值来满足should子句中的条件。