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 的出现使得我们的存储.检索数据更快 ...
随机推荐
- HDU - 5413 CRB and Roads
CRB and Roads Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...
- Said
呃~~生活中的每天都会经历很多事儿,而影响结果的无非就是人对事物的处理方式和对事物的处理态度~~ 在上学期间,有时考试不理想,我都会进行反思,对不该错的题巩固在三,对不会做的题查缺补漏……因为不能不思 ...
- 01-VS充当IIS的配置步骤
一. 背景 在实际开发中,经常会遇到需要在线调试,比如:第三方支付的回调.App接口借助PostMan工具测试,需要在代码上直接加断点,来进行调试,VS默认是不支持这种方式,需要手动配置一下,才能达到 ...
- centos redis集群搭建
说明: 10.0.0.111部署6500,6501,6502三个主节点 10.0.0.222部署6500,6501,6502三个备份节点 1.安装redis:略 2.配置内核参数 # 配置 vm.ov ...
- 词典的实现(4)-使用Hash方式来实现词典
1,实现思路 public class HashedDictionary<K, V> implements DictionaryInterface<K, V>, Seriali ...
- IT阅读——关于“业务”
本文转自http://www.cnblogs.com/beijiguangyong/archive/2012/11/12/2767054.html 开发当中常常听说“业务”这个词,什么“业务为王”之类 ...
- pyinstaller 打包不成功,提示inporterror 缺少xlrd、xlwt
问题:pyinstaller 打包不成功,提示inporterror 缺少xlrd.xlwt 解决:将 pypiwin 230 改为 219
- 【Gradle】Gradle环境配置
Windows环境 下载 作者下载的是gradle-4.1-all.zip,下载地址:http://services.gradle.org/distributions 环境配置 GRADLE_HOME ...
- Debian & CentOS建立本地iso源
在宿舍搞开发的时候经常遇到有些工具需要安装,没有网络,这时候只能靠mount本地的iso镜像来搞,结果像Debian有3张安装光盘,CentOS有2张光盘,有时候安装包不在第一张光盘里,而在第二张光盘 ...
- java 多线程二
java 多线程一 java 多线程二 java 多线程三 java 多线程四 线程中断: /** * Created by root on 17-9-30. */ public class Test ...