[Elasticsearch] 多字段搜索 (六) - 自定义_all字段,跨域查询及精确值字段
自定义_all字段
在元数据:_all字段中,我们解释了特殊的_all字段会将其它所有字段中的值作为一个大字符串进行索引。尽管将所有字段的值作为一个字段进行索引并不是非常灵活。如果有一个自定义的_all字段用来索引人名,另外一个自定义的_all字段用来索引地址就更好了。
ES通过字段映射中的copy_to参数向我们提供了这一功能:
PUT /my_index
{
"mappings": {
"person": {
"properties": {
"first_name": {
"type": "string",
"copy_to": "full_name"
},
"last_name": {
"type": "string",
"copy_to": "full_name"
},
"full_name": {
"type": "string"
}
}
}
}
}
现在first_name和last_name字段中的值会被拷贝到full_name字段中。
有了这个映射,我们可以通过first_name字段查询名字,last_name字段查询姓氏,或者full_name字段查询姓氏和名字。
NOTE
first_name和last_name字段的映射和full_name字段的索引方式的无关。full_name字段会从其它两个字段中拷贝字符串的值,然后仅根据full_name字段自身的映射进行索引。
跨域查询(Cross-fields Queries)
如果你在索引文档前就能够自定义_all字段的话,那么使用_all字段就是一个不错的方法。但是,ES同时也提供了一个搜索期间的解决方案:使用类型为cross_fields的multi_match查询。cross_fields类型采用了一种以词条为中心(Term-centric)的方法,这种方法和best_fields及most_fields采用的以字段为中心(Field-centric)的方法有很大的区别。它将所有的字段视为一个大的字段,然后在任一字段中搜索每个词条。
为了阐述以字段为中心和以词条为中心的查询的区别,看看以字段为中心的most_fields查询的解释(译注:通过validate-query API得到):
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "most_fields",
"operator": "and",
"fields": [ "first_name", "last_name" ]
}
}
}
operator设为了and,表示所有的词条都需要出现。
对于一份匹配的文档,peter和smith两个词条都需要出现在相同的字段中,要么是first_name字段,要么是last_name字段:
(+first_name:peter +first_name:smith) (+last_name:peter +last_name:smith)
而已词条为中心的方法则使用了下面这种逻辑:
+(first_name:peter last_name:peter) +(first_name:smith last_name:smith)
换言之,词条peter必须出现在任一字段中,同时词条smith也必须出现在任一字段中。
cross_fields类型首先会解析查询字符串来得到一个词条列表,然后在任一字段中搜索每个词条。仅这个区别就能够解决在以字段为中心的查询中提到的3个问题中的2个,只剩下倒排文档频度的不同这一问题。
幸运的是,cross_fields类型也解决了这个问题,从下面的validate-query请求中可以看到:
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "cross_fields",
"operator": "and",
"fields": [ "first_name", "last_name" ]
}
}
}
它通过混合(Blending)字段的倒排文档频度来解决词条频度的问题:
+blended("peter", fields: [first_name, last_name]) +blended("smith", fields: [first_name, last_name])
换言之,它会查找词条smith在first_name和last_name字段中的IDF值,然后使用两者中较小的作为两个字段最终的IDF值。因为smith是一个常见的姓氏,意味着它也会被当做一个常见的名字。
NOTE
为了让cross_fields查询类型能以最佳的方式工作,所有的字段都需要使用相同的解析器。使用了相同的解析器的字段会被组合在一起形成混合字段(Blended Fields)。
如果你包含了使用不同解析链(Analysis Chain)的字段,它们会以和best_fields相同的方被添加到查询中。比如,如果我们将title字段添加到之前的查询中(假设它使用了一个不同的解析器),得到的解释如下所示:
(+title:peter +title:smith) ( +blended("peter", fields: [first_name, last_name]) +blended("smith", fields: [first_name, last_name]) )
当使用了minimum_should_match以及operator参数时,这一点尤为重要。
逐字段提升(Per-field Boosting)
使用cross_fields查询相比使用自定义_all字段的一个优点是你能够在查询期间对个别字段进行提升。
对于first_name和last_name这类拥有近似值的字段,也许提升是不必要的,但是如果你通过title和description字段来搜索书籍,那么你或许会给予title字段更多的权重。这可以通过前面介绍的caret(^)语法来完成:
GET /books/_search
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "cross_fields",
"fields": [ "title^2", "description" ]
}
}
}
能够对个别字段进行提升带来的优势应该和对多个字段执行查询伴随的代价进行权衡,因为如果使用自定义的_all字段,那么只需要要对一个字段进行查询。选择能够给你带来最大收益的方案。
精确值字段(Exact-value Fields)
在结束对于多字段查询的讨论之前的最后一个话题是作为not_analyzed类型的精确值字段。在multi_match查询中将not_analyzed字段混合到analyzed字段中是没有益处的。
原因可以通过validate-query进行简单地验证,假设我们将title字段设置为not_analyzed:
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "cross_fields",
"fields": [ "title", "first_name", "last_name" ]
}
}
}
因为title字段时没有被解析的,它会以将整个查询字符串作为一个词条进行搜索!
title:peter smith ( blended("peter", fields: [first_name, last_name]) blended("smith", fields: [first_name, last_name]) )
很显然该词条在title字段的倒排索引中并不存在,因此永远不可能被找到。在multi_match查询中避免使用not_analyzed字段。
[Elasticsearch] 多字段搜索 (六) - 自定义_all字段,跨域查询及精确值字段的更多相关文章
- Springboot如何优雅的解决ajax+自定义headers的跨域请求
1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...
- Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]
1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...
- 前端MVC Vue2学习总结(六)——axios与跨域HTTP请求、Lodash工具库
一.axios Vue更新到2.0之后宣告不再对vue-resource更新,推荐使用axios,axios是一个用于客户端与服务器通信的组件,axios 是一个基于Promise 用于浏览器和 no ...
- SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)
上个示例(SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API))是基于JavaScript,运行在web browser内去访问REST AP ...
- 跨域 - 自定义 jsonp实现跨域
问题:在现代浏览器中默认是不允许跨域. 办法:通过jsonp实现跨域 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的.但是,在页面上引入不同域上的js脚本文件却是 ...
- 原创:【ajax | axios跨域简单请求+复杂请求】自定义header头Token请求Laravel5后台【亲测可用】
如标题:我想在ajax的header头增加自定义Token进行跨域api认证并调用,api使用laravel5编写,如何实现? 首先,了解下CORS简单请求和复杂请求. -- CORS简单请求 -- ...
- Elasticsearch系列---初识搜索
概要 本篇主要介绍搜索的报文结构含义.搜索超时时间的处理过程,提及了一下多索引搜索和轻量搜索,最后将精确搜索与全文搜索做了简单的对比. 空搜索 搜索API最简单的形式是不指定索引和类型的空搜索,它将返 ...
- Elasticsearch 全字段搜索_all,query_string查询,不进行分词
最近在使用ELasitcsearch的时候,需要用到关键字搜索,因为是全字段搜索,就需要使用_all字段的query_string进行搜索. 但是在使用的时候,遇到问题了.我们的业务并不需要分词,我在 ...
- ElasticSearch 2 (15) - 深入搜索系列之多字段搜索
ElasticSearch 2 (15) - 深入搜索系列之多字段搜索 摘要 查询很少是简单的一句话匹配(one-clause match)查询.很多时候,我们需要用相同或不同的字符串查询1个或多个字 ...
随机推荐
- nginx配置、域名、前端代码部署
服务器上部署nginx,部署多个独立的代码,用nginx做域名映射的配置方法: 修改/usr/local/nginx/conf/nginx.conf文件,重点是最后一行,include /data/n ...
- javascript--自定义弹出登陆窗口(弹出窗)
web开发中浏览器对象封装了诸如prompt.alert.confirm等弹出框,但是有的弹出框并不能满足开发需要,需要我们自己定义弹出框,诸如用户登陆框.消息提示框等.本文利用弹出用户登陆框示例,对 ...
- JavaScript--文本框中只允许输入数字的操作(其他字符不显示)
在web网页中,尤其是某些提交表单操作,需要验证文本框输入内容,本文利用文本框键盘事件和事件对象,对文本框只允许输入数字方法进行总结. 1.键盘事件 keydown ---->键盘按下事件 ...
- 使用Win32DiskImager后重置SD卡
再1.Windows diskpart命令 diskpart 2.列出所有的磁盘 lisk disk 3.选择U盘所在的磁盘 4.清除磁盘 clean 5.创建主分区 create primary p ...
- Apache Maven(五):插件
Maven的插件分如下两种: build plugins:该插件在项目构建阶段执行,它们都在<build>标签中设置. reporting plugins : 该插件在网站生成期间执行,他 ...
- Hadoop(3)-Hadoop介绍
Hadoop三大发行版本 Hadoop三大发行版本:Apache.Cloudera.Hortonworks. Apache版本最原始(最基础)的版本,对于入门学习最好. Cloudera在大型互联网企 ...
- ruby require的使用
引用单个文件 例: 引用当前rb同目录下的file_to_require.rb先介绍3种方法 require File.join(__FILE__, '../file_to_require') req ...
- 初识python 文件读取 保存
上一章最后一题的答案:infors.sort(key=lambda x:x['age'])print(infors)--->[{'name': 'laowang', 'age': 23}, {' ...
- webug学习(1)
webug的题目,比较简单,拿来巩固一哈. 1. 一看就知道是注入漏洞了,啥也不说sqlmap直接开炮. 先-u 之后-u 网址 --current-db 获取当前网址的数据库 所以当前数据库就是 p ...
- 03---Nginx配置文件
#启动子进程程序默认用户#user nobody;#一个主进程和多个工作进程.工作进程是单进程的,且不需要特殊授权即可运行:这里定义的是工作进程数量worker_processes 1; #全局错误日 ...