码迷,mamicode.com
首页 > 其他好文 > 详细

Elasticsearch深入8

时间:2019-06-18 23:04:56      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:toc   服务   singleton   let   创建   响应   需要   releases   pos   

搜索推荐,search as you type

百度 --> elas --> elasticsearch --> elasticsearch权威指南

 

GET /my_index/my_type/_search

{

  "query": {

    "match_phrase_prefix": {

      "title": "hello d"

    }

  }

}

原理跟match_phrase类似,唯一的区别,就是把最后一个term作为前缀去搜索

 hello就是去进行match,搜索对应的doc

w,会作为前缀,去扫描整个倒排索引,找到所有w开头的doc

然后找到所有doc中,即包含hello,又包含w开头的字符的doc

根据你的slop去计算,看在slop范围内,能不能让hello w,正好跟doc中的hello和w开头的单词的position相匹配

 也可以指定slop,但是只有最后一个term会作为前缀

 max_expansions:指定prefix最多匹配多少个term,超过这个数量就不继续匹配了,限定性能

 默认情况下,前缀要扫描所有的倒排索引中的term,去查找w打头的单词,但是这样性能太差。可以用max_expansions限定,w前缀最多匹配多少个term,就不再继续搜索倒排索引了。

 尽量不要用,因为,最后一个前缀始终要去扫描大量的索引,性能可能会很差

通过ngram分词机制实现index-time搜索推荐

什么是ngram 

quick,5种长度下的ngram

在将新的doc放入es中的的时候已经将词做了处理了

 hello world

h

he

hel

hell

hello          会将filed安装这种才分方式        

 hello we

w                        

wo

wor

worl

world

min ngram = 1

设置最大(就是分3层或者3级)max ngram = 3

h

he

hel

搜索的时候,不用再根据一个前缀,然后扫描整个倒排索引了; 简单的拿前缀去倒排索引中匹配即可,如果匹配上了,那么就好了; match,全文检索

PUT /my_index 

{

    "settings": {

        "analysis": {

            "filter": {

                "autocomplete_filter": {

                    "type": "edge_ngram",

                    "min_gram": 1,

                    "max_gram": 20

                }

            },

            "analyzer": {

                "autocomplete": {

                    "type":      "custom",

                    "tokenizer": "standard",

                    "filter": [

                        "lowercase",

                        "autocomplete_filter"

                    ]

                }

            }

        }

    }

}

测试分词规则

GET /my_index/_analyze

{

  "analyzer": "autocomplete",

  "text": "hello world"

}就可以看见效果了 没有贴图

 

PUT /my_index/_mapping/my_type

{

  "properties": {

      "title": {

          "type":"string",

          "analyzer": "autocomplete",

          "search_analyzer": "standard"

      }

  }

}//添加分词规则

GET /my_index/my_type/_search

{

  "query": {

    "match_phrase": {

      "title": "hello w"

    }

  }

}推荐效果就OK了

如果用match,只有hello的也会出来,全文检索,只是分数比较低

推荐使用match_phrase,要求每个term都有,而且position刚好靠着1位,符合我们的期望

容忍包含不相关的内容但是采取降低分数

搜索包含java,不包含spark的doc,但是这样子很死板

搜索包含java,尽量不包含spark的doc,如果包含了spark,不会说排除掉这个doc,而是说将这个doc的分数降低

包含了negative term的doc,分数乘以negative boost,分数降低

GET /forum/article/_search

{

  "query": {

    "boosting": {

      "positive": {

        "match": {

          "content": "java"

        }

      },

      "negative": {

        "match": {

          "content": "spark"

        }

      },

      "negative_boost": 0.2

    }

  }

}

如果你压根儿不需要相关度评分,直接走constant_score加filter,所有的doc分数都是1,没有评分的概念了

GET /forum/article/_search

{

  "query": {

    "bool": {

      "should": [

        {

          "constant_score": {

            "query": {

              "match": {

                "title": "java"

              }

            }

          }

        },

        {

          "constant_score": {

            "query": {

              "match": {

                "title": "spark"

              }

            }

          }

        }

      ]

    }

  }

}

IK中文分词器的安装和使用

地址 : https://github.com/medcl/elasticsearch-analysis-ik/tags 选择合适的版本

1、ik配置文件

 ik配置文件地址:es/plugins/ik/config目录

 IKAnalyzer.cfg.xml:用来配置自定义词库

main.dic:ik原生内置的中文词库,总共有27万多条,只要是这些单词,都会被分在一起

quantifier.dic:放了一些单位相关的词

suffix.dic:放了一些后缀

surname.dic:中国的姓氏

stopword.dic:英文停用词

 ik原生最重要的两个配置文件

 main.dic:包含了原生的中文词语,会按照这个里面的词语去分词

stopword.dic:包含了英文的停用词

 停用词,stopword

 a the and at but

 一般,像停用词,会在分词的时候,直接被干掉,不会建立在倒排索引中

2、自定义词库

 (1)自己建立词库:每年都会涌现一些特殊的流行词,网红,蓝瘦香菇,喊麦,鬼畜,一般不会在ik的原生词典里

 自己补充自己的最新的词语,到ik的词库里面去

 IKAnalyzer.cfg.xml:ext_dict,custom/mydict.dic

 补充自己的词语,然后需要重启es,才能生效

 (2)自己建立停用词库:比如了,的,啥,么,我们可能并不想去建立索引,让人家搜索

 custom/ext_stopword.dic,已经有了常用的中文停用词,可以补充自己的停用词,然后重启es

★修改IK分词器源码来基于mysql热更新词库

热更新

 

每次都是在es的扩展词典中,手动添加新词语,很坑

(1)每次添加完,都要重启es才能生效,非常麻烦

(2)es是分布式的,可能有数百个节点,你不能每次都一个一个节点上面去修改

 

es不停机,直接我们在外部某个地方添加新的词语,es中立即热加载到这些新词语

 热更新的方案

 (1)修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库

(2)基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新

 用第一种方案,第二种,ik git社区官方都不建议采用,觉得不太稳定

 1、下载源码

 https://github.com/medcl/elasticsearch-analysis-ik/tree/v5.2.0

 ik分词器,是个标准的java maven工程,直接导入eclipse就可以看到源码

 2、修改源码

 Dictionary类,169行:Dictionary单例类的初始化方法,在这里需要创建一个我们自定义的线程,并且启动它

HotDictReloadThread类:就是死循环,不断调用Dictionary.getSingleton().reLoadMainDict(),去重新加载词典

Dictionary类,389行:this.loadMySQLExtDict();

Dictionary类,683行:this.loadMySQLStopwordDict();

 3、mvn package打包代码

 target\releases\elasticsearch-analysis-ik-5.2.0.zip

 4、解压缩ik压缩包

 将mysql驱动jar,放入ik的目录下

 5、修改jdbc相关配置

 6、重启es

 观察日志,日志中就会显示我们打印的那些东西,比如加载了什么配置,加载了什么词语,什么停用词

 7、在mysql中添加词库与停用词

 8、分词实验,验证热更新生效

效果展示

技术图片

添加数据库扩展词

技术图片

 

 成功加载至es中,打印相关日志

 技术图片

 再次运行相关查询

 技术图片

 

Elasticsearch深入8

标签:toc   服务   singleton   let   创建   响应   需要   releases   pos   

原文地址:https://www.cnblogs.com/jiahaoJAVA/p/11048382.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!