中文搜索使用IK分词器,IK分词器安装:
https://blog.csdn.net/wwd0501/article/details/78258274
因要支持拼音提示,故需安装拼音插件,拼音插件安装以及IK+拼音使用地址:
https://blog.csdn.net/wwd0501/article/details/80622669
1、创建index,设置setting
curl -XPUT "http://localhost:9200/medcl/" -d '
"index": {
"analysis": {
"analyzer": {
"default": {
"tokenizer": "ik_max_word"
"pinyin_analyzer": {
"tokenizer": "shopmall_pinyin"
"first_py_letter_analyzer": {
"tokenizer": "first_py_letter"
"full_pinyin_letter_analyzer": {
"tokenizer": "full_pinyin_letter"
"tokenizer": {
"shopmall_pinyin": {
"keep_joined_full_pinyin": "true",
"keep_first_letter": "true",
"keep_separate_first_letter": "false",
"lowercase": "true",
"type": "pinyin",
"limit_first_letter_length": "16",
"keep_original": "true",
"keep_full_pinyin": "true",
"keep_none_chinese_in_joined_full_pinyin": "true"
"first_py_letter": {
"type": "pinyin",
"keep_first_letter": true,
"keep_full_pinyin": false,
"keep_original": false,
"limit_first_letter_length": 16,
"lowercase": true,
"trim_whitespace": true,
"keep_none_chinese_in_first_letter": false,
"none_chinese_pinyin_tokenize": false,
"keep_none_chinese": true,
"keep_none_chinese_in_joined_full_pinyin": true
"full_pinyin_letter": {
"type": "pinyin",
"keep_separate_first_letter": false,
"keep_full_pinyin": false,
"keep_original": false,
"limit_first_letter_length": 16,
"lowercase": true,
"keep_first_letter": false,
"keep_none_chinese_in_first_letter": false,
"none_chinese_pinyin_tokenize": false,
"keep_none_chinese": true,
"keep_joined_full_pinyin": true,
"keep_none_chinese_in_joined_full_pinyin": true
2、mapping
curl -XPOST http://localhost:9200/medcl/folks/_mapping -d'
"folks": {
"properties": {
"name": {
"type": "completion",
"fields": {
"pinyin": {
"type": "completion",
"analyzer": "pinyin_analyzer"
"keyword_pinyin": {
"type": "completion",
"analyzer": "full_pinyin_letter_analyzer"
"keyword_first_py": {
"type": "completion",
"analyzer": "first_py_letter_analyzer"
3、初始化测试数据
curl -XPOST http://localhost:9200/medcl/folks/ -d'{"name":"苹果"}'
curl -XPOST http://localhost:9200/medcl/folks/_search -d '
"size": 0,
"_source": "name",
"suggest": {
"my-suggest-1": {
"text": "苹",
"completion": {
"field": "name",
"size": 20
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
"hits": {
"total": 0,
"max_score": 0,
"hits": []
"suggest": {
"my-suggest-1": [{
"text": "苹",
"offset": 0,
"length": 1,
"options": [{
"text": "苹果",
"_index": "medcl",
"_type": "folks",
"_id": "AWRLJ9lrsB4QSA8b-FrJ",
"_score": 1,
"_source": {
"name": "苹果"
6、代码实现,基于elasticsearch5.x版本
* 1、检测搜索词是中文还是拼音
* 2、若是中文,直接按照name字段提示
* 3、若是拼音(拼音+汉字),先按照name.keyword_pinyin获取,若是无结果按照首字母name.keyword_first_py获取
Java代码:
package test;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class EsSuggestTest01 {
private static Client client;
@Before
public void init() throws UnknownHostException {
client = ElasticsearchConfiguration.getClient();
@After
public void close() {
ElasticsearchConfiguration.close();
@Test
public void test(){
String index = "medcl";
String type = "folks";
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
String text = "苹";
String field = "name";
if(checkLetter(text)) {
field = "name.keyword_pinyin";
} else if(checkChinese(text)) {
field = "name";
} else {
field = "name.keyword_pinyin";
Set<String> results = getSuggestWord(index, type, field, text, queryBuilder);
//结果为空且是拼音,可以尝试拼音首字母提示
if(results.size() == 0 && checkLetter(text)) {
field = "nicknames.nicknameSuggest.keyword_first_py";
results = getSuggestWord(index, type, field, text, queryBuilder);
for (String result : results) {
System.out.println(result);
* Description:提示词,支持中文、拼音、首字母等(注意要去掉_source信息)
* 1、检测搜索词是中文还是拼音
* 2、若是中文,直接按照name字段提示
* 3、若是拼音(拼音+汉字),先按照name.keyword_pinyin获取,若是无结果按照首字母name.keyword_first_py获取
* SearchRequestBuilder的size要设置为0,否则显示hits结果
* searchRequestBuilder.setSize(0);
* _source 由于磁盘读取和网络传输开销,可以影响性能的大小,为了节省一些网络开销,请从_source 使用源过滤中过滤掉不必要的字段以最小化 _source大小
* 可以采用过滤的形式,也可以直接不显示_source
* 1、searchRequestBuilder.setFetchSource("name", null); 过滤形式
* 2、searchRequestBuilder.setFetchSource(false) 直接不显示_source
* @author wangweidong
* CreateTime: 2018年6月28日 下午2:39:47
* @param index
* @param type
* @param field
* @param text
* @return
public static Set<String> getSuggestWord(String index, String type, String field, String text, QueryBuilder queryBuilder) {
//过滤相同的提示词,Es5.2版本不支持过滤掉重复的建议,故需自己对ES返回做去重处理,Es6.1以上版本可以通过skip_duplicates字段处理,skip_duplicates表示是否应过滤掉重复的建议(默认为false)
Set<String> results = new TreeSet<String>();
CompletionSuggestionBuilder suggestionBuilder = new CompletionSuggestionBuilder(field);
suggestionBuilder.text(text);
suggestionBuilder.size(20);
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("my-suggest-1", suggestionBuilder);
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index).setTypes(type);
searchRequestBuilder.setExplain(false);
searchRequestBuilder.setSize(0);
searchRequestBuilder.setQuery(queryBuilder);
searchRequestBuilder.suggest(suggestBuilder);
searchRequestBuilder.setFetchSource(false);
// searchRequestBuilder.setFetchSource("name", null);
SearchResponse resp = searchRequestBuilder.execute().actionGet();
Suggest sugg = resp.getSuggest();
CompletionSuggestion suggestion = sugg.getSuggestion("my-suggest-1");
List<CompletionSuggestion.Entry> list = suggestion.getEntries();
for (int i = 0; i < list.size(); i++) {
List<? extends Suggest.Suggestion.Entry.Option> options = list.get(i).getOptions();
for (Suggest.Suggestion.Entry.Option op : options) {
results.add(op.getText().toString());
return results;
* 只包含字母
* @return 验证成功返回true,验证失败返回false
public static boolean checkLetter(String cardNum) {
String regex = "^[A-Za-z]+$";
return Pattern.matches(regex, cardNum);
* 验证中文
* @param chinese 中文字符
* @return 验证成功返回true,验证失败返回false
public static boolean checkChinese(String chinese) {
String regex = "^[\u4E00-\u9FA5]+$";
return Pattern.matches(regex,chinese);
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
public class ElasticsearchConfiguration {
private static TransportClient client;
private static String clusterName;
private static List<String> clusterNodes;
static {
clusterName = "shop-es";
clusterNodes = Arrays.asList("http://172.16.32.6:9300","http://172.16.32.8:9300");
private ElasticsearchConfiguration() {
public static Client getClient() throws UnknownHostException {
Settings settings = Settings.builder().put("cluster.name", clusterName).build();
client = new PreBuiltTransportClient(settings);
for (String node : clusterNodes) {
URI host = URI.create(node);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host.getHost()), host.getPort()));
return client;
public static void close() {
client.close();
参考官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-suggesters-completion.html
Elasticsearch 中提供类似的搜索功能。
答案就在Suggesters API。 Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回。 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester,分别是:
Term Suggester
completion suggest也叫自动完成,搜索推荐,搜索提示 ,一般多叫自动完成,即auto completion。
比如说我们在百度,搜索,你现在搜索“大话西游” --&gt;
百度,自动给你提示,“大话西游电影”,“大话西游小说”, “大话西游手游”等,不用你把所有你想要输入的文本都输入...
Completion Suggester是Elasticsearch SearchAPIs中一种,主要用于输入框的自动补齐功能。
我将通过字或者拼音首字母推荐成语的java程序作为实战演示。
项目地址:https://github.com/tangwanggong/week-project/tree/master/week-1
成语数据来源:https://github.com/pwxcoo...
&amp;quot;settings&amp;quot;: {
&amp;quot;analysis&amp;quot;: {
&amp;quot;analyzer&amp;quot;: {
&amp;quot;ik_pinyin_analyzer&amp;quot;: {
文章目录1. Completion Suggester 简介2.存储doc文档2. 查询使用3. 跳过重复的suggestions4. Fuzzy queries4. Regex queries
1. Completion Suggester 简介
有关不使用 suggest 者的更灵活的search-as-you-type类型的搜索,请参阅search_as_you_type字段类型。
completion suggester 提供自动completion/search-as-you-type功能。这是一
下面说说在es中的种实现搜索提示的功能,基于completion suggest 进行实现,其在实际应用中搜索性能更加高效。
假如文档库里有一堆关于大话西游的,比如,“大话西游电影”,“大话西游小说”,"大话西游舞台剧"等,这里我们需要搜索以"大话西游"开头的文档。
1、自定义index,及字段分词属性,这里用IK中文分词器:
PUT /news_website
"mappings": {
"news" : {
"properties" : {
"title" .
在之前的某一篇中,我们使用了es的前缀搜索,获得了文档根据前缀进行匹配的效果,如下图所示,
下面说说在es中的另一种实现搜索提示的功能,基于completion suggest 进行实现,其在实际应用中搜索性能更加高效,
假如文档库里有一堆关于大话西游的,比如,“大话西游电影”,“大话西游小说”,"大话西游舞台剧"等,这里我们需要搜索以"大话西游"开头的文档,
1、自定义index,及字段分词属...
在lucene里面,suggest 的支持非常完善,可以随心所欲的定制; 但是在es中使用起来就没有那么方便了。 es给suggest 分类4类:term ;phrase; completion; context; 目前最新版本是es1.2.1 这一块也还在不断完善中; term
suggester 是根据某词元在制定的字段中出现的频次来做出提示; phrase suggester 是给ter
首先:对索引重构: "suggest": { "type": "completion" },在索引中加入这个关键词字段;创建Suggest类:public class HouseSuggest {
private String input;
private int weight = 10; // 默认权重
public String getInput() {...
ES使用completion suggest做自动建议时,建议多开一个子字段,如下示例,假设要根据title字段做自动建议,那么该字段的类型就得改为completion,不过建议不要改原字段的类型,多开一个子字段title.suggest,类型设置为completion,然后之后的suggest针对title.suggest字段做操作就好,参考mapping如下:
"title": {
"type": "text",
"analyzer": "ik_max_word"
Completion suggester 提供自动完成/输入时搜索功能。 这是一个导航功能,可以在用户键入内容时指导他们获得相关结果,从而提高搜索精度。 它并不用于拼写纠正或诸如为term 及 phrase 提供建议。对于 suggester,请你阅读我之前的文章:
Elasticsearch:如何实现短语建议 - phrase suggester
Elasticsearch:如何在 Elasticsearch中 查询相似的术语 (suggest API)
理想情况下,自动完成功能应与.