ElasticSearch - How to search for a part of a word with ElasticSearch
Search a part of word with ElasticSearch
来自stackoverflow
https://stackoverflow.com/questions/6467067/how-to-search-for-a-part-of-a-word-with-elasticsearch
场景还原
// 初始化数据
POST /my_idx/my_type/_bulk
{"index": {"_id": "1"}}
{"name": "John Doeman", "function": "Janitor"}
{"index": {"_id": "2"}}
{"name": "Jane Doewoman", "function": "Teacher"}
{"index": {"_id": "3"}}
{"name": "Jimmy Jackal", "function": "Student"}
Question
ElasticSearch中有数据如下:
{
"_id" : "1",
"name" : "John Doeman",
"function" : "Janitor"
}
{
"_id" : "2",
"name" : "Jane Doewoman",
"function" : "Teacher"
}
{
"_id" : "3",
"name" : "Jimmy Jackal",
"function" : "Student"
}
现在期望搜索所有包含Doe的文档
// 并没有返回任何文档
GET /my_idx/my_type/_search?q=Doe
// 返回一个文档
GET /my_idx/my_type/_search?q=Doeman
提问者还更换了分词器,改用请求体的方式,但这也不行:
GET /my_idx/my_type/_search
{
"query": {
"term": {
"name": "Doe"
}
}
}
后来使用了nGram的tokenizer和filter
{
"index": {
"index": "my_idx",
"type": "my_type",
"bulk_size": "100",
"bulk_timeout": "10ms",
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "my_ngram_tokenizer",
"filter": [
"my_ngram_filter"
]
}
},
"filter": {
"my_ngram_filter": {
"type": "nGram",
"min_gram": 1,
"max_gram": 1
}
},
"tokenizer": {
"my_ngram_tokenizer": {
"type": "nGram",
"min_gram": 1,
"max_gram": 1
}
}
}
}
}
引入了另外一个问题:任意的查询都可以返回所有文档
Answers
首先这是一个分词引起的问题,索引默认情况下使用standard分词器,对于文档:
{
"_id" : "1",
"name" : "John Doeman",
"function" : "Janitor"
}
{
"_id" : "2",
"name" : "Jane Doewoman",
"function" : "Teacher"
}
{
"_id" : "3",
"name" : "Jimmy Jackal",
"function" : "Student"
}
索引后会得到这样一个映射,这里只考虑了name字段的分词:
| segment | document id list |
|---|---|
| john | 1 |
| doeman | 1 |
| jane | 2 |
| doewoman | 2 |
| jimmy | 3 |
| jackal | 3 |
那么现在考虑我们的搜索
Search 1
GET /my_idx/my_type/_search?q=Doe
standard分词器会将Doe分析为doe,然后到索引表中查找,并不会找到doe这个索引,因此返回空
Search 2
GET /my_idx/my_type/_search?q=Doeman
standard分词器会将Doeman分析为doeman,然后到索引表中找到了该索引,会发现只有doc ID 1包含该索引,所以只返回一个文档
Search 3
GET /my_idx/my_type/_search
{
"query": {
"term": {
"name": "Doe"
}
}
}
term查询,Doe还是Doe,不会被分析器分析,但是Doe在索引表中依然是不存在的,所以这个方法也无法返回任何文档。
Search 4
额外说明,题主并没有用这种方式试过
GET /my_idx/my_type/_search
{
"query": {
"term": {
"name": "Doeman"
}
}
}
不要以为这样就能找到了,因为term不进行分析,所以直接从索引表中找Doeman也是没有任何文档匹配的,除非把Doeman改为doeman
解决方案
总结了一下stackoverflow上的答案,目前有这么几种可行方案:
- 正则匹配法
- 通配符匹配法
- 前缀匹配法
- nGram分词器法
正则匹配法
GET my_idx/my_type/_search
{
"query": {
"regexp": {
"name": "doe.*"
}
}
}
通配符匹配法
使用query_string配合通配符进行查询,需要注意的是,通配符查找可能使用大量内存且效率低下
后缀匹配(前导通配符)是非常重的操作(e.g. "*ing"),索引中所有的term都会被查找一遍,可以通过allow_leading_wildcard来关闭后缀匹配功能
GET my_idx/my_type/_search
{
"query": {
"query_string": {
"default_field": "name",
"query": "Doe*"
}
}
}
前缀匹配法
原答案说使用prefix,但是prefix并没有对查询进行分析,这里我们使用match_phrase_prefix
GET my_idx/my_type/_search
{
"query": {
"match_phrase_prefix": {
"name": {
"query": "Doe",
"max_expansions": 10
}
}
}
}
nGram分词器法
创建索引
PUT my_idx
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 3,
"token_chars": [
"letter",
"digit"
]
}
}
}
}
}
测试一下分词器
POST my_idx/_analyze
{
"analyzer": "my_analyzer",
"text": "Doeman"
}
// response
{
"tokens": [
{
"token": "Doe",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "oem",
"start_offset": 1,
"end_offset": 4,
"type": "word",
"position": 1
},
{
"token": "ema",
"start_offset": 2,
"end_offset": 5,
"type": "word",
"position": 2
},
{
"token": "man",
"start_offset": 3,
"end_offset": 6,
"type": "word",
"position": 3
}
]
}
再查就可以查到了。而题主虽然使用了ngram,但是min_gram和max_gram都配置为1
长度越小,匹配到的文档越多,但匹配的质量会越差
长度越大,检索到的文档越匹配。推荐使用长度为3的tri-gram。官方文档对此有详细介绍
ElasticSearch - How to search for a part of a word with ElasticSearch的更多相关文章
- ElasticSearch报 EsThreadPoolExecutor[search, queue capacity = 1000, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@c0efba
ElasticSearch报以下错误的解决办法: "type": "es_rejected_execution_exception", "reason ...
- Elasticsearch: 使用URI Search
在Elasticsearch中,我们可以使用_search终端进行搜索.这个在我之前的文章 "开始使用Elasticsearch (2)" 中有很多的描述.针对这种搜索,我们可以使 ...
- ElasticSearch: SearchContextMissingException[No search context found for id [173690]]
这个原因是scroll的时间设置不够久,设久一些就可以了. ----------------------------------- 原文:https://www.cnblogs.com/chenmz1 ...
- Elasticsearch通关教程(五):如何通过SQL查询Elasticsearch
前言 这篇博文本来是想放在全系列的大概第五.六篇的时候再讲的,毕竟查询是在索引创建.索引文档数据生成和一些基本概念介绍完之后才需要的.当前面的一些知识概念全都讲解完之后再讲解查询是最好的,但是最近公司 ...
- 【docker Elasticsearch】Rest风格的分布式开源搜索和分析引擎Elasticsearch初体验
概述: Elasticsearch 是一个分布式.可扩展.实时的搜索与数据分析引擎. 它能从项目一开始就赋予你的数据以搜索.分析和探索的能力,这是通常没有预料到的. 它存在还因为原始数据如果只是躺在磁 ...
- 学习用Node.js和Elasticsearch构建搜索引擎(3):使用curl命令操作elasticsearch
使用Elasticsearch不免要提到curl工具,curl是利用URL语法在命令行方式下工作的开源文件传输工具.官网地址:https://curl.haxx.se/ 因为elasticsearch ...
- elasticsearch安装与使用(4)-- 安装中文分词插件elasticsearch 的 jdbc
前言 elasticsearch(下面简称ES)使用jdbc连接mysql比go-mysql-elasticsearch的elasticsearch-river-jdbc能够很好的支持增量数据更新的问 ...
- elasticsearch配置文件里的一些坑 [Failed to load settings from [elasticsearch.yml]]
这里整理几个空格引起的问题. 版本是elasticsearch-2.3.0 或者elasticsearch-rtf-master Exception in thread "main" ...
- 几篇关于MySQL数据同步到Elasticsearch的文章---第五篇:logstash-input-jdbc实现mysql 与elasticsearch实时同步深入详解
文章转载自: https://blog.csdn.net/laoyang360/article/details/51747266 引言: elasticsearch 的出现使得我们的存储.检索数据更快 ...
随机推荐
- Math.random()和UUID.randomUUID().toString()性能对比【纯原】
Math.random()和UUID.randomUUID().toString()性能对比 不言而喻,因为Math.random()不需要保证唯一性,所做的操作远比UUID消耗更小的性能, 在部分要 ...
- ThinkPHP 3.2 用户注册邮箱验证帐号找回密码
一.前言 当然现在有的网站也有手机短信的方式找回密码,原理就是通过发送验证码来验明正身,和发送邮件验证一样,最终还是要通过重置密码来完成找回密码的流程. 本文将使用PHP+Mysql+jQuery来实 ...
- VSCode 拓展插件推荐
想让VS code干活快起来,插件少不了,开始吧: 快捷键:Ctrl+Shift+X打开插件搜索安装即可 (安装的插件通常会保存在这个目录:C:\Users\你的系统登录用户如administrato ...
- .NET面试题系列(十五)yong
Redis为什么使用单进程单线程方式也这么快 Redis遍历所有key的两个命令 -- KEYS 和 SCAN 一致性Hash算法 利用一致性哈希水平拆分MySql单表 单例模式 锁 双重锁 单例模 ...
- 淘淘商城之SSM框架整合概要
一.后台系统所用的技术 1)框架:Spring + SpringMVC + Mybatis: 2)前端:EasyUI: 3)数据库:mysql 二.创建数据库 1)安装mysql数据库: 2)在mys ...
- Android常用网络请求框架Volley Retrofit (okHttp)
Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient.在 Android 5.0 的时候 Google 就不推荐使用 HttpClient ...
- Docker相关
1.理念 通过对应用组件的封装.分发.部署.运行等生命周期的管理,使用户的App(可以是一个Web应用或数据库应用等)及其运行环境能够做到“一次封装,处处运行”. 2.一句话总结 解决运行环境和配置问 ...
- python 历险记(四)— python 中常用的 json 操作
目录 引言 基础知识 什么是 JSON? JSON 的语法 JSON 对象有哪些特点? JSON 数组有哪些特点? 什么是编码和解码? 常用的 json 操作有哪些? json 操作需要什么库? 如何 ...
- pytorch官网上两个例程
caffe用起来太笨重了,最近转到pytorch,用起来实在不要太方便,上手也非常快,这里贴一下pytorch官网上的两个小例程,掌握一下它的用法: 例程一:利用nn 这个module构建网络,实现 ...
- Python3学习笔记22-文件读写
读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操 ...