ES中如何实现带有数字的精准前缀匹配?

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 2088 次浏览 • 2022-03-29 17:32 • 来自相关话题

Elasticsearch如何查找两个圆形区域的差集中的文档?

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 3812 次浏览 • 2021-02-20 19:15 • 来自相关话题

Linux上启动Kibana总提示端口被占用怎么处理?

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 5204 次浏览 • 2020-02-17 16:28 • 来自相关话题

Elasticsearch查询总结合集(二)

zkbhj 发表了文章 • 0 个评论 • 1472 次浏览 • 2019-11-27 14:37 • 来自相关话题

多字段搜索(Multifield Search)

查询很少是只拥有一个match查询子句的查询。我们经常需要对一个或者多个字段使用相同或者不同的查询字符串进行搜索,这意味着我们需要将多个查询子句和它们得到的相关度分值以一种有意义的方式进行合并。

也许我们正在寻找一本名为战争与和平的书,它的作者是Leo Tolstoy。也许我们正在使用"最少应该匹配(Minimum Should Match)"来搜索ES中的文档。另外我们也可能会寻找拥有名为John而姓为Smith的用户。

在本章中我们会讨论一些构建多字段搜索的工具,以及如何根据你的实际情况来决定使用哪种方案。

多个查询字符串(Multiple Query Strings)

处理字段查询最简单的方法是将搜索词条对应到特定的字段上。如果我们知道战争与和平是标题,而Leo Tolstoy是作者,那么我们可以简单地将每个条件当做一个match子句,然后通过bool查询将它们合并:
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "War and Peace" }},
{ "match": { "author": "Leo Tolstoy" }}
]
}
}
}bool查询采用了一种"匹配越多越好(More-matches-is-better)"的方法,因此每个match子句的分值会被累加来得到文档最终的_score。匹配两个子句的文档相比那些只匹配一个子句的文档的分值会高一些。

当然,你并不是只能使用match子句:bool查询可以包含任何其他类型的查询,包括其它的bool查询。我们可以添加一个子句来指定我们希望的译者:
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "War and Peace" }},
{ "match": { "author": "Leo Tolstoy" }},
{ "bool": {
"should": [
{ "match": { "translator": "Constance Garnett" }},
{ "match": { "translator": "Louise Maude" }}
]
}}
]
}
}
}我们为什么将译者的查询子句放在一个单独的bool查询中?所有的4个match查询都是should子句,那么为何不将译者的查询子句和标题及作者的查询子句放在同一层次上呢?

答案在于分值是如何计算的。bool查询会运行每个match查询,将它们的分值相加,然后乘以匹配的查询子句的数量,最后除以所有查询子句的数量。相同层次的每个子句都拥有相同的权重。在上述查询中,bool查询中包含的译者查询子句只占了总分值的三分之一。如果我们将译者查询子句放到和标题及作者相同的层次上,就会减少标题和作者子句的权重,让它们各自只占四分之一。

设置子句优先级

上述查询中每个子句占有三分之一的权重也许并不是我们需要的。相比译者字段,我们可能对标题和作者字段更有兴趣。我们对查询进行调整来让标题和作者相对更重要。

在所有可用措施中,我们可以采用的最简单的方法是boost参数。为了增加title和author字段的权重,我们可以给它们一个大于1的boost值:GET /_search
{
"query": {
"bool": {
"should": [
{ "match": {
"title": {
"query": "War and Peace",
"boost": 2
}}},
{ "match": {
"author": {
"query": "Leo Tolstoy",
"boost": 2
}}},
{ "bool": {
"should": [
{ "match": { "translator": "Constance Garnett" }},
{ "match": { "translator": "Louise Maude" }}
]
}}
]
}
}
}以上的title和k字段的boost值为2。 嵌套的bool查询自居的默认boost值为k。

通过试错(Trial and Error)的方式可以确定"最佳"的boost值:设置一个boost值,执行测试查询,重复这个过程。一个合理boost值的范围在1和10之间,也可能是15。比它更高的值的影响不会起到很大的作用,因为分值会被规范化(Normalized)。

单一查询字符串(Single Query String)

bool查询是多字段查询的中流砥柱。在很多场合下它都能很好地工作,特别是当你能够将不同的查询字符串映射到不同的字段时。

问题在于,现在的用户期望能够在一个地方输入所有的搜索词条,然后应用能够知道如何为他们得到正确的结果。所以当我们把含有多个字段的搜索表单称为高级搜索(Advanced Search)时,是有一些讽刺意味的。高级搜索虽然对用户而言会显得更"高级",但是实际上它的实现方式更简单。

对于多词,多字段查询并没有一种万能的方法。要得到最佳的结果,你需要了解你的数据以及如何使用恰当的工具。

了解你的数据

当用户的唯一输入就是一个查询字符串时,你会经常碰到以下三种情况:

最佳字段(Best fields)

当搜索代表某些概念的单词时,例如"brown fox",几个单词合在一起表达出来的意思比单独的单词更多。类似title和body的字段,尽管它们是相关联的,但是也是互相竞争着的。文档在相同的字段中应该有尽可能多的单词(译注:搜索的目标单词),文档的分数应该来自拥有最佳匹配的字段。

多数字段(Most fields)

一个用来调优相关度的常用技术是将相同的数据索引到多个字段中,每个字段拥有自己的分析链(Analysis Chain)。

主要字段会含有单词的词干部分,同义词和消除了变音符号的单词。它用来尽可能多地匹配文档。

相同的文本可以被索引到其它的字段中来提供更加精确的匹配。一个字段或许会包含未被提取词干的单词,另一个字段是包含了变音符号的单词,第三个字段则使用shingle来提供关于单词邻近度(Word Proximity)的信息。

以上这些额外的字段扮演者signal的角色,用来增加每个匹配的文档的相关度分值。越多的字段被匹配则意味着文档的相关度越高。

跨字段(Cross fields)

对于一些实体,标识信息会在多个字段中出现,每个字段中只含有一部分信息:
 
Person:first_name 和 last_nameBook:title,author 和 descriptionAddress:street,city,country 和 postcode

此时,我们希望在任意字段中找到尽可能多的单词。我们需要在多个字段中进行查询,就好像这些字段是一个字段那样。

以上这些都是多词,多字段查询,但是每种都需要使用不同的策略。我们会在本章剩下的部分解释每种策略。 查看全部
多字段搜索(Multifield Search)

查询很少是只拥有一个match查询子句的查询。我们经常需要对一个或者多个字段使用相同或者不同的查询字符串进行搜索,这意味着我们需要将多个查询子句和它们得到的相关度分值以一种有意义的方式进行合并。

也许我们正在寻找一本名为战争与和平的书,它的作者是Leo Tolstoy。也许我们正在使用"最少应该匹配(Minimum Should Match)"来搜索ES中的文档。另外我们也可能会寻找拥有名为John而姓为Smith的用户。

在本章中我们会讨论一些构建多字段搜索的工具,以及如何根据你的实际情况来决定使用哪种方案。

多个查询字符串(Multiple Query Strings)

处理字段查询最简单的方法是将搜索词条对应到特定的字段上。如果我们知道战争与和平是标题,而Leo Tolstoy是作者,那么我们可以简单地将每个条件当做一个match子句,然后通过bool查询将它们合并:
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "War and Peace" }},
{ "match": { "author": "Leo Tolstoy" }}
]
}
}
}
bool查询采用了一种"匹配越多越好(More-matches-is-better)"的方法,因此每个match子句的分值会被累加来得到文档最终的_score。匹配两个子句的文档相比那些只匹配一个子句的文档的分值会高一些。

当然,你并不是只能使用match子句:bool查询可以包含任何其他类型的查询,包括其它的bool查询。我们可以添加一个子句来指定我们希望的译者:
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "War and Peace" }},
{ "match": { "author": "Leo Tolstoy" }},
{ "bool": {
"should": [
{ "match": { "translator": "Constance Garnett" }},
{ "match": { "translator": "Louise Maude" }}
]
}}
]
}
}
}
我们为什么将译者的查询子句放在一个单独的bool查询中?所有的4个match查询都是should子句,那么为何不将译者的查询子句和标题及作者的查询子句放在同一层次上呢?

答案在于分值是如何计算的。bool查询会运行每个match查询,将它们的分值相加,然后乘以匹配的查询子句的数量,最后除以所有查询子句的数量。相同层次的每个子句都拥有相同的权重。在上述查询中,bool查询中包含的译者查询子句只占了总分值的三分之一。如果我们将译者查询子句放到和标题及作者相同的层次上,就会减少标题和作者子句的权重,让它们各自只占四分之一。

设置子句优先级

上述查询中每个子句占有三分之一的权重也许并不是我们需要的。相比译者字段,我们可能对标题和作者字段更有兴趣。我们对查询进行调整来让标题和作者相对更重要。

在所有可用措施中,我们可以采用的最简单的方法是boost参数。为了增加title和author字段的权重,我们可以给它们一个大于1的boost值:
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": {
"title": {
"query": "War and Peace",
"boost": 2
}}},
{ "match": {
"author": {
"query": "Leo Tolstoy",
"boost": 2
}}},
{ "bool": {
"should": [
{ "match": { "translator": "Constance Garnett" }},
{ "match": { "translator": "Louise Maude" }}
]
}}
]
}
}
}
以上的title和k字段的boost值为2。 嵌套的bool查询自居的默认boost值为k。

通过试错(Trial and Error)的方式可以确定"最佳"的boost值:设置一个boost值,执行测试查询,重复这个过程。一个合理boost值的范围在1和10之间,也可能是15。比它更高的值的影响不会起到很大的作用,因为分值会被规范化(Normalized)。

单一查询字符串(Single Query String)

bool查询是多字段查询的中流砥柱。在很多场合下它都能很好地工作,特别是当你能够将不同的查询字符串映射到不同的字段时。

问题在于,现在的用户期望能够在一个地方输入所有的搜索词条,然后应用能够知道如何为他们得到正确的结果。所以当我们把含有多个字段的搜索表单称为高级搜索(Advanced Search)时,是有一些讽刺意味的。高级搜索虽然对用户而言会显得更"高级",但是实际上它的实现方式更简单。

对于多词,多字段查询并没有一种万能的方法。要得到最佳的结果,你需要了解你的数据以及如何使用恰当的工具。

了解你的数据

当用户的唯一输入就是一个查询字符串时,你会经常碰到以下三种情况:

最佳字段(Best fields)

当搜索代表某些概念的单词时,例如"brown fox",几个单词合在一起表达出来的意思比单独的单词更多。类似title和body的字段,尽管它们是相关联的,但是也是互相竞争着的。文档在相同的字段中应该有尽可能多的单词(译注:搜索的目标单词),文档的分数应该来自拥有最佳匹配的字段。

多数字段(Most fields)

一个用来调优相关度的常用技术是将相同的数据索引到多个字段中,每个字段拥有自己的分析链(Analysis Chain)。

主要字段会含有单词的词干部分,同义词和消除了变音符号的单词。它用来尽可能多地匹配文档。

相同的文本可以被索引到其它的字段中来提供更加精确的匹配。一个字段或许会包含未被提取词干的单词,另一个字段是包含了变音符号的单词,第三个字段则使用shingle来提供关于单词邻近度(Word Proximity)的信息。

以上这些额外的字段扮演者signal的角色,用来增加每个匹配的文档的相关度分值。越多的字段被匹配则意味着文档的相关度越高。

跨字段(Cross fields)

对于一些实体,标识信息会在多个字段中出现,每个字段中只含有一部分信息:
 
  • Person:first_name 和 last_name
  • Book:title,author 和 description
  • Address:street,city,country 和 postcode


此时,我们希望在任意字段中找到尽可能多的单词。我们需要在多个字段中进行查询,就好像这些字段是一个字段那样。

以上这些都是多词,多字段查询,但是每种都需要使用不同的策略。我们会在本章剩下的部分解释每种策略。

Elasticsearch查询总结合集

zkbhj 发表了文章 • 0 个评论 • 1776 次浏览 • 2019-11-26 16:38 • 来自相关话题

一、term、terms查询(精确查询)
 
term query会去倒排索引中寻找确切的term,它并不知道分词器的存在,这种查询适合keyword、numeric、date等明确值的

term:查询某个字段里含有某个关键词的文档GET /customer/doc/_search/
{
"query": {
"term": {
"title": "blog"
}
}
}terms:查询某个字段里含有多个关键词的文档
GET /customer/doc/_search/
{
"query": {
"terms": {
"title": [ "blog","first"]
}
}
}
二、match查询(模糊查询)

match query 知道分词器的存在,会对field进行分词操作,然后再查询。GET /customer/doc/_search/
{
"query": {
"match": {
"title": "my ss" #它和term区别可以理解为term是精确查询,这边match模糊查询;match会对my ss分词为两个单词,然后term对认为这是一个单词
}
}
}match_all:查询所有文档
GET /customer/doc/_search/
{
"query": {
"match_all": {}
}
}multi_match:可以指定多个字段
GET /customer/doc/_search/
{
"query": {
"multi_match": {
"query" : "blog",
"fields": ["name","title"] #只要里面一个字段包含值 blog 既可以
}
}
}
 三、match_phrase:短语匹配查询

ES引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变

_source:当我们希望返回结果只是一部分字段时,可以加上_source
GET /customer/doc/_search/
{
"_source":["title"], #只返回title字段
"query": {
"match_all": {}
}
}
 四、排序

使用sort实现排序(类似sql):desc 降序,asc升序

fuzzy实现模糊查询

value:查询的关键字

boost:查询的权值,默认值是1.0

min_similarity:设置匹配的最小相似度,默认值0.5,对于字符串,取值0-1(包括0和1);对于数值,取值可能大于1;对于日期取值为1d,1m等,1d等于1天

prefix_length:指明区分词项的共同前缀长度,默认是0GET /customer/doc/_search/
{

"query": {
"fuzzy": {
"name": {
"value": "blg"
}
}
}
}

#返回:
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.19178805,
"hits": [
{
"_index": "customer",
"_type": "doc",
"_id": "1",
"_score": 0.19178805,
"_source": {
"name": "blog",
"tags": [
"testing"
],
"title": "i am a doc"
}
}
]
}
} 查看全部
一、term、terms查询(精确查询)
 
term query会去倒排索引中寻找确切的term,它并不知道分词器的存在,这种查询适合keyword、numeric、date等明确值的

term:查询某个字段里含有某个关键词的文档
GET /customer/doc/_search/
{
"query": {
"term": {
"title": "blog"
}
}
}
terms:查询某个字段里含有多个关键词的文档
GET /customer/doc/_search/
{
"query": {
"terms": {
"title": [ "blog","first"]
}
}
}

二、match查询(模糊查询)

match query 知道分词器的存在,会对field进行分词操作,然后再查询。
GET /customer/doc/_search/
{
"query": {
"match": {
"title": "my ss" #它和term区别可以理解为term是精确查询,这边match模糊查询;match会对my ss分词为两个单词,然后term对认为这是一个单词
}
}
}
match_all:查询所有文档
GET /customer/doc/_search/
{
"query": {
"match_all": {}
}
}
multi_match:可以指定多个字段
GET /customer/doc/_search/
{
"query": {
"multi_match": {
"query" : "blog",
"fields": ["name","title"] #只要里面一个字段包含值 blog 既可以
}
}
}

 三、match_phrase:短语匹配查询

ES引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变

_source:当我们希望返回结果只是一部分字段时,可以加上_source
GET /customer/doc/_search/
{
"_source":["title"], #只返回title字段
"query": {
"match_all": {}
}
}

 四、排序

使用sort实现排序(类似sql):desc 降序,asc升序

fuzzy实现模糊查询

value:查询的关键字

boost:查询的权值,默认值是1.0

min_similarity:设置匹配的最小相似度,默认值0.5,对于字符串,取值0-1(包括0和1);对于数值,取值可能大于1;对于日期取值为1d,1m等,1d等于1天

prefix_length:指明区分词项的共同前缀长度,默认是0
GET /customer/doc/_search/
{

"query": {
"fuzzy": {
"name": {
"value": "blg"
}
}
}
}

#返回:
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.19178805,
"hits": [
{
"_index": "customer",
"_type": "doc",
"_id": "1",
"_score": 0.19178805,
"_source": {
"name": "blog",
"tags": [
"testing"
],
"title": "i am a doc"
}
}
]
}
}

Elasticsearch查询房源时如何使用自定义函数进行文档排序?

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 3431 次浏览 • 2019-11-04 16:54 • 来自相关话题

Elasticsearch:向量空间(Vector Space Model)

zkbhj 发表了文章 • 0 个评论 • 2228 次浏览 • 2019-08-08 10:37 • 来自相关话题

向量空间(Vector Space Model)提供比较多术语查询的一种方式,单个分数代表文档与查询的匹配程度,为了做到这点,这个模型将文档和查询都以向量的形式表示:

一个向量实际上就是包含很多数字的一个一维数组,例如:
[1,2,5,22,3,8]在向量空间模型里,向量里的每个数字都代表一个术语的权重,和TF/IDF计算方式类似。

尽管 TF/IDF 是向量空间模型计算术语权重的默认方式,但不是唯一的方式,ElasticSearch还有其他模型(如:Okapi-BM25)。TF/IDF是默认的因为它是个经检验过的简单、高效算法,可以提供高质量的搜索结果。

如果我们有查询“happy hippopotamus”,常见词 happy 的权重较低,不常见词 hippopotamus 权重较高,假设 happy的权重是2,hippopotamus 的权重是5,我们可以将这个二维向量——[2,5]——在坐标系下作条直线,线起于(0,0)点终于(2,5)点:





 
现在,假想我们有三个文档:
 
I am happy in summer.After Christmas I'm a hippopotamus.The happy hippopotamus helped Harry.

我们可以为每个文档都创建一个包括每个查询术语(happy 和 hippopotamus)权重的向量,然后将这些向量置入同一个坐标系中: 
文档 1:(happy,____________)——[2,0]文档 2:(_____,hippopotamus)——[0,5]文档 3:(happy,hippopotamus)——[2,5]

向量之间是可以比较的,只需要测量查询向量和文档向量之间的角度就可以得到每个文档的相关度,文档1与查询之间的角度最大,所以相关度低;文档2与查询间的角度较小,所以更相关;文档3与查询的角度正好吻合,完全匹配。

在实际中,只有二维向量(两个术语的查询)可以在平面上表示,幸运的是,线性代数——作为数学中处理向量的一个分支——为我们提供了计算两个多维向量间角度工具,这意味着我们可以使用如上同样的方式来解释多个术语的查询。

关于比较两个向量的更多信息可以在 余弦近似度(cosine similarity) 中看到

现在我们讨论了分数计算的基本理论,我们可以继续了解Lucene是如何实现分数计算的。 查看全部
向量空间(Vector Space Model)提供比较多术语查询的一种方式,单个分数代表文档与查询的匹配程度,为了做到这点,这个模型将文档和查询都以向量的形式表示:

一个向量实际上就是包含很多数字的一个一维数组,例如:
[1,2,5,22,3,8]
在向量空间模型里,向量里的每个数字都代表一个术语的权重,和TF/IDF计算方式类似。

尽管 TF/IDF 是向量空间模型计算术语权重的默认方式,但不是唯一的方式,ElasticSearch还有其他模型(如:Okapi-BM25)。TF/IDF是默认的因为它是个经检验过的简单、高效算法,可以提供高质量的搜索结果。

如果我们有查询“happy hippopotamus”,常见词 happy 的权重较低,不常见词 hippopotamus 权重较高,假设 happy的权重是2,hippopotamus 的权重是5,我们可以将这个二维向量——[2,5]——在坐标系下作条直线,线起于(0,0)点终于(2,5)点:

613455-20160308175355585-430511576.png

 
现在,假想我们有三个文档:
 
  1. I am happy in summer.
  2. After Christmas I'm a hippopotamus.
  3. The happy hippopotamus helped Harry.


我们可以为每个文档都创建一个包括每个查询术语(happy 和 hippopotamus)权重的向量,然后将这些向量置入同一个坐标系中: 
  • 文档 1:(happy,____________)——[2,0]
  • 文档 2:(_____,hippopotamus)——[0,5]
  • 文档 3:(happy,hippopotamus)——[2,5]


向量之间是可以比较的,只需要测量查询向量和文档向量之间的角度就可以得到每个文档的相关度,文档1与查询之间的角度最大,所以相关度低;文档2与查询间的角度较小,所以更相关;文档3与查询的角度正好吻合,完全匹配。

在实际中,只有二维向量(两个术语的查询)可以在平面上表示,幸运的是,线性代数——作为数学中处理向量的一个分支——为我们提供了计算两个多维向量间角度工具,这意味着我们可以使用如上同样的方式来解释多个术语的查询。

关于比较两个向量的更多信息可以在 余弦近似度(cosine similarity) 中看到

现在我们讨论了分数计算的基本理论,我们可以继续了解Lucene是如何实现分数计算的。

安装Elasticsearch过程中可能会遇到的问题集锦

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 3715 次浏览 • 2019-06-24 13:57 • 来自相关话题

如何安装ElasticSearch-head插件?

回复

zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 4578 次浏览 • 2018-07-24 09:23 • 来自相关话题