jjzjj

elasticsearch term & match 查询

风老魔 2023-08-23 原文

1. 准备数据

PUT h1/doc/1
{
  "name": "rose",
  "gender": "female",
  "age": 18,
  "tags": ["白", "漂亮", "高"]
}

PUT h1/doc/2
{
  "name": "lila",
  "gender": "female",
  "age": 18,
  "tags": ["黑", "漂亮", "高"]
}

PUT h1/doc/3
{
  "name": "john",
  "gender": "male",
  "age": 18,
  "tags": ["黑", "帅", "高"]
}

运行结果:

{
  "_index" : "h1",
  "_type" : "doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

2. match 查询

2.1 match 按条件查询

# 查询性别是男性的结果
GET h1/doc/_search
{
  "query": {
    "match": {
      "gender": "male"
    }
  }
}

查询结果:

{
  "took" : 59,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "h1",		# 索引
        "_type" : "doc",		# 文档类型
        "_id" : "3",			# 文档唯一 id
        "_score" : 0.2876821,	# 打分机制打出来的分数
        "_source" : {			# 查询结果
          "name" : "john",
          "gender" : "male",
          "age" : 18,
          "tags" : [
            "黑",
            "帅",
            "高"
          ]
        }
      }
    ]
  }
}

2.2 match_all 查询全部

# 查询 h1 中所有文档
GET h1/doc/_search
{
  "query": {
    "match_all": {}
  }
}

match_all的值为空,表示没有查询条件,那就是查询全部。就像select * from table_name 一样。

查询结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "lila",
          "gender" : "female",
          "age" : 18,
          "tags" : [
            "黑",
            "漂亮",
            "高"
          ]
        }
      },
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "rose",
          "gender" : "female",
          "age" : 18,
          "tags" : [
            "白",
            "漂亮",
            "高"
          ]
        }
      },
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "john",
          "gender" : "male",
          "age" : 18,
          "tags" : [
            "黑",
            "帅",
            "高"
          ]
        }
      }
    ]
  }
}

2.3 match_phrase 短语查询

match 查询时散列映射,包含了我们希望搜索的字段和字符串,即只要文档中有我们希望的那个关键字,但也会带来一些问题。

es 会将文档中的内容进行拆分,对于英文来说可能没有太大的影响,但是中文短语就不太适用,一旦拆分就会失去原有的含义,比如以下:

1、准备数据:

PUT t1/doc/1
{
  "title": "中国是世界上人口最多的国家"
}

PUT t1/doc/2
{
  "title": "美国是世界上军事实力最强大的国家"
}

PUT t1/doc/3
{
  "title": "北京是中国的首都"
}

2、先使用 match 查询含有中国的文档:

GET t1/doc/_search
{
  "query": {
    "match": {
      "title": "中国"
    }
  }
}

查询结果:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 0.68324494,
    "hits" : [
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.68324494,
        "_source" : {
          "title" : "中国是世界上人口最多的国家"
        }
      },
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "北京是中国的首都"
        }
      },
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.39556286,
        "_source" : {
          "title" : "美国是世界上军事实力最强大的国家"
        }
      }
    ]
  }
}

发现三篇文档都被返回,与我们的预期有偏差;这是因为 title 中的内容被拆分成一个个单独的字,而 id=2 的文档包含了 字也符合,所以也被返回了。es 自带的中文分词处理不太好用,后面可以使用 ik 中文分词器来处理。

3、match_phrase 查询短语

不过可以使用 match_phrase 来匹配短语,将上面的 match 换成 match_phrase 试试:

# 短语查询
GET t1/doc/_search
{
  "query": {
    "match_phrase": {
      "title": "中国"
    }
  }
}

查询结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "中国是世界上人口最多的国家"
        }
      },
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "北京是中国的首都"
        }
      }
    ]
  }
}

4、slop 间隔查询

当我们要查询的短语,中间有别的词时,可以使用 slop 来跳过。比如上述要查询 中国世界,这个短语中间被 隔开了,这时可以使用 slop 来跳过,相当于正则中的中国.*?世界

# 短语查询,查询中国世界,加 slop 
GET t1/doc/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "中国世界",
        "slop": 1
      }
    }
  }
}

查询结果:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.7445889,
    "hits" : [
      {
        "_index" : "t1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.7445889,
        "_source" : {
          "title" : "中国是世界上人口最多的国家"
        }
      }
    ]
  }
}

2.4 match_phrase_prefix 最左前缀查询

场景:当我们要查询的词只能想起前几个字符时

# 最左前缀查询,查询名字为 rose 的文档
GET h1/doc/_search
{
  "query": {
    "match_phrase_prefix": {
      "name": "ro"
    }
  }
}

查询结果:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "rose",
          "gender" : "female",
          "age" : 18,
          "tags" : [
            "白",
            "漂亮",
            "高"
          ]
        }
      }
    ]
  }
}

限制结果集

最左前缀查询很费性能,返回的是一个很大的集合,一般很少使用,使用的时候最好对结果集进行限制,max_expansions 参数可以设置最大的前缀扩展数量:

# 最左前缀查询
GET h1/doc/_search
{
  "query": {
    "match_phrase_prefix": {
      "gender": {
        "query": "fe",
        "max_expansions": 1
      }
    }
  }
}

查询结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "lila",
          "gender" : "female",
          "age" : 18,
          "tags" : [
            "黑",
            "漂亮",
            "高"
          ]
        }
      },
      {
        "_index" : "h1",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "rose",
          "gender" : "female",
          "age" : 18,
          "tags" : [
            "白",
            "漂亮",
            "高"
          ]
        }
      }
    ]
  }
}

2.5 multi_match 多字段查询

1、准备数据:

# 多字段查询
PUT t3/doc/1
{
  "title": "maggie is beautiful girl",
  "desc": "beautiful girl you are beautiful so"
}

PUT t3/doc/2
{
  "title": "beautiful beach",
  "desc": "I like basking on the beach,and you? beautiful girl"
}

2、查询包含 beautiful 字段的文档:

GET t3/doc/_search
{
  "query": {
    "multi_match": {
      "query": "beautiful",				# 要查询的词
      "fields": ["desc", "title"]		# 要查询的字段
    }
  }
}

还可以当做 match_phrasematch_phrase_prefix使用,只需要指定type类型即可:

GET t3/doc/_search
{
  "query": {
    "multi_match": {
      "query": "gi",
      "fields": ["title"],
      "type": "phrase_prefix"
    }
  }
}

GET t3/doc/_search
{
  "query": {
    "multi_match": {
      "query": "girl",
      "fields": ["title"],
      "type": "phrase"
    }
  }
}

3. term 查询

3.1 初始 es 的分析器

term 查询用于精确查询,但是不适用于 text 类型的字段查询。

在此之前我们先了解 es 的分析机制,默认的标准分析器会对文档进行:

  • 删除大多数的标点符号
  • 将文档拆分为单个词条,称为 token
  • token 转换为小写

最后保存到倒排序索引上,而倒排序索引用来查询,如 Beautiful girl 经过分析后是这样的:

POST _analyze
{
  "analyzer": "standard",
  "text": "Beautiful girl"
}


# 结果,转换为小写了
{
  "tokens" : [
    {
      "token" : "beautiful",
      "start_offset" : 0,
      "end_offset" : 9,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "girl",
      "start_offset" : 10,
      "end_offset" : 14,
      "type" : "<ALPHANUM>",
      "position" : 1
    }
  ]
}

3.2 term 查询

1、准备数据:

# 创建索引,自定义 mapping,后面会讲到
PUT t4
{
  "mappings": {
    "doc":{
      "properties":{
        "t1":{
          "type": "text"    # 定义字段类型为 text
        }
      }
    }
  }
}

PUT t4/doc/1
{
  "t1": "Beautiful girl!"
}

PUT t4/doc/2
{
  "t1": "sexy girl!"
}

2、match 查询:

GET t4/doc/_search
{
  "query": {
    "match": {
      "t1": "Beautiful girl!"
    }
  }
}

经过分析后,会得到 beautiful、girl 两个 token,然后再去 t4 索引上去查询,会返回两篇文档:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "t4",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "Beautiful girl"
        }
      },
      {
        "_index" : "t4",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.2876821,
        "_source" : {
          "title" : "sex girl"
        }
      }
    ]
  }
}

3、但是我们只想精确查询包含 Beautiful girl 的文档,这时就需要使用 term 来精确查询:

GET t4/doc/_search
{
  "query": {
    "term": {
      "title": "beautiful"
    }
  }
}

查询结果:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "t4",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "title" : "Beautiful girl"
        }
      }
    ]
  }
}

注意:term 查询不适用于类型是 text 的字段,可以使用 match 查询;另外 Beautiful 经过分析后变为 beautiful,查询时使用 Beautiful 是查询不到的~

3.3 查询多个

精确查询多个字段:

GET t4/doc/_search
{
  "query": {
    "terms": {
      "title": ["beautiful", "sex"]
    }
  }
}

有关elasticsearch term & match 查询的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  5. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  9. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  10. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

随机推荐