「es模糊java」es模糊查询语法
本篇文章给大家谈谈es模糊java,以及es模糊查询语法对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、Java查询ES会占用Linux文件句柄吗?
- 2、Java代码查询es 的索引是yellow的状态,怎么可以查询不报错?
- 3、ES实现模糊搜索
- 4、Es 模糊查询的方式
- 5、Es实现百万级数据快速检索
- 6、es使用与原理4 -- phrase match ,slop近似匹配,搜索推荐等等
Java查询ES会占用Linux文件句柄吗?
这是肯定的,ES是吃内存的,肯定会占用句柄数的,但是你说的这种情况模糊不清,我也不太了解,如果ES合理的话,不会出现这种问题,你可以查看一下是哪个进程占用了句柄,不就一目了然了?
命令:
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more
得到两列数据,第一列是句柄数,第二列是id
ps aef|grep id
然后,一目了然
请采纳,谢谢
Java代码查询es 的索引是yellow的状态,怎么可以查询不报错?
建议提前检查,为yellow直接提醒运维去维护为green。不过我这边用的es6.2.3yellow是正常查询的。建议你检查一下环境配置应该不是yellow的问题。试了一下;为red都可以正常查询的(java代码查询结果和下图es-head查询结果一致)
ES实现模糊搜索
最近使用ES时,有一个简单的需求,要求实现按照某个字段实现类似mysql中的like查询。
这里记录下实现方式。
这里java的api使用的是RestHighLevelClient,RestHighLevelClient从字面意思理解就是restful风格的高级别的客户端,底层封装的是一个http连接池,当需要执行 update、index、delete操作时,直接从连接池中取出一个连接,然后发送http请求到ElasticSearch服务端,服务端基于Netty接收请求。新版本的elasticsearch java client 都推荐用RestHighLevelClient去连接ES集群。
以下为实现方式:
这里要实现模糊匹配的字段为:plateNo(业务上表示车牌号)
以下是一开始的实现方法。plateNo字段type为text,现在保存了一条值为京A00000的数据
刚开始时候一直无法实现,可以搜索 京 查询出数据;或者搜索 A00000 查询到数据,但是使用全部 京A00000 查询数据为空。
后来确定原因,因为为text,所以这个字段在保存时会分词,所以索引中不会有 京A00000,因此解决思路就是该字段type指定为keyword,同时使用查询时指定查询时使用keyword,如下。
boolQueryBuilder.must(QueryBuilders.wildcardQuery("plateNo.keyword", (" 京A00000 ")));
解决问题。
Es 模糊查询的方式
Es 模糊查询的方式
要求:
Es查询:
查询工单信息, 输入 “测试”,查出 form_name 为字段中有查询出含有符合内容的数据
match:分词模糊查询:
比如“Everything will be OK, All is well”,会被分词一个一个单词(不是单个字母)
match_phrase :短语模糊查询
match_phrase是短语搜索,即它会将给定的短语(phrase)当成一个完整的查询条件。
比如查询 “Everything will”,会当成一个完整的短语进行查询, 会查出含有该查询条件的内容。
如果是查询单个字母,match就不管用了,那该如何处理呢?
wildcard:通配符模糊查询:
匹配任意字符
匹配0个或多个字符
记录是存在的,但是没有查出来? 因为分词的影响,添加keyword 进行处理
Wildcard 性能会比较慢。如果非必要,尽量避免在开头加通配符 ? 或者 *,这样会明显降低查询性能
如果查询的内容非空,怎么处理? 直接用*
总结:
Es 模糊查询, 分词的用match; 短语的用match_phrase;查询任意的,用wildcard通配符,注意查询的内容是否分词,分词的添加keyword,查询非空的情况,用*。
Es实现百万级数据快速检索
在用户点击一篇采购文章,会匹配到该文章全部相关内容。所有数据是存在ES中的,百万量级。恩~要用python写一个接口。通过查找资料,通过 ES模糊搜索 可以实现。
prefix的匹配一般是处理不分词的场景,将会匹配articleID中以”J”开头的doc。prefix不会计算revelance score,只是作一个过滤的操作,和filter唯一的区别是filter会缓存结果,而prefix不会。前缀越短要处理的doc越多,性能越差。
?会匹配任意字符,*会匹配0个或多个字符。性能根prefix一样差,必须要扫描整个倒排索引。
[0-9]:指定范围内的数字
[a-z]:指定范围内的字幕
.:一个字符
+:前面的正则表达式可以出现一次或多次
正则的搜索同样会扫描全表,性能也会很差
fuzziness参数调整纠正的次数
通常不会直接用上述搜索,而会用下面的搜索:
在es中,使用组合条件查询是其作为搜索引擎检索数据的一个强大之处,在前几篇中,简单演示了es的查询语法,但基本的增删改查功能并不能很好的满足复杂的查询场景,比如说我们期望像mysql那样做到拼接复杂的条件进行查询该如何做呢?es中有一种语法叫bool,通过在bool里面拼接es特定的语法可以做到大部分场景下复杂条件的拼接查询,也叫复合查询
首先简单介绍es中常用的组合查询用到的关键词,
filter:过滤,不参与打分
must:如果有多个条件,这些条件都必须满足 and与
should:如果有多个条件,满足一个或多个即可 or或
must_not:和must相反,必须都不满足条件才可以匹配到 !非
发生 描述
must
该条款(查询)必须出现在匹配的文件,并将有助于得分。
filter
子句(查询)必须出现在匹配的文档中。然而不像 must查询的分数将被忽略。Filter子句在过滤器上下文中执行,这意味着评分被忽略,子句被考虑用于高速缓存。
should
子句(查询)应该出现在匹配的文档中。如果 bool查询位于查询上下文中并且具有mustor filter子句,则bool即使没有should查询匹配,文档也将匹配该查询 。在这种情况下,这些条款仅用于影响分数。如果bool查询是过滤器上下文 或者两者都不存在,must或者filter至少有一个should查询必须与文档相匹配才能与bool查询匹配。这种行为可以通过设置minimum_should_match参数来显式控制 。
must_not
子句(查询)不能出现在匹配的文档中。子句在过滤器上下文中执行,意味着评分被忽略,子句被考虑用于高速缓存。因为计分被忽略,0所有文件的分数被返回。
下面用实验演示一下上述查询的相关语法,
1、首先,我们创建一个索引,并且在索引里添加几条数据,方便后面使用,
我这里直接批量插入数据,也可以通过PUT的语法单条执行插入,
POST /forum/article/_bulk
{ "index": { "_id": 1 }}
{ "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2019-07-01","title":"java contains hadoop and spark","topic":"java" }
{ "index": { "_id": 2 }}
{ "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2019-07-02",title":"php contains admin","topic":"java and php" }
{ "index": { "_id": 3 }}
{ "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2019-07-03" ,title":"spark is new language","topic":"spark may use java"}
{ "index": { "_id": 4 }}
{ "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2019-07-04" ,title":"hadoop may involve java","topic":"big data used"}
或者使用put语法
PUT /forum/article/4
{
"articleID": "QQPX-R-3956-#aD8",
"userID": 2,
"hidden": true,
"postDate": "2019-07-04",
"title": "hadoop may involve java",
"topic": "big data used"
}
4条数据插入成功,
2、termQuery,term查询不分词,类似于mysql的where filedName = ? 语法,即精准匹配,比如我们查询articleID = XHDK-A-1293-#fJ3的这条数据,
GET /forum/article/_search
{
"query": {
"term": {
"articleID.keyword":"XHDK-A-1293-#fJ3"
}
}
}
2、must查询,即查询的条件中必须匹配的字段,例如,查询title中必须包含java的数据,
GET /forum/article/_search
{
"query": {
"bool": {
"must": [
{"term":{"title":"hadoop"}}
]
}
}
}
查出两条数据
如果是should呢?如下语法,即查询title中包含hadoop或者topic中包含spark,二者满足其一即可,
GET /forum/article/_search
{
"query": {
"bool": {
"should": [
{"term":{"title":"hadoop"}},
{"term": {"topic": "spark"}}
]
}
}
}
查询出3条数据,
must和should结合使用,
最后再来一个比较复杂的嵌套查询,我们先看一下这条sql语句,
select *
from forum.article
where article_id=‘XHDK-A-1293-#fJ3’
or (article_id=‘JODL-X-1937-#pV7’ and post_date=‘2017-01-01’),
对应着转化为es的复合查询语法是怎样的呢?拆分来看,就是一个should语句的嵌套,
GET /forum/article/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"articleID.keyword": "XHDK-A-1293-#fJ3"
}
},
{
"bool": {
"must": [
{
"term": {
"articleID.keyword":"JODL-X-1937-#pV7"
}
},
{
"term": {
"postDate":"2019-07-01"
}
}
]
}
}
}
}
查询到一条结果,按照这种思路,如果我们对一个复杂的查询不知道如何构建查询语句时,可以考虑先按照sql的语法进行拆分,然后再组织es查询语句是个不错的突破口,
到这里,可能我们会有疑问,复合条件中的term查询和单纯的match区别在哪里呢?既然都是查询,究竟原理有何不同呢?
我们知道match query是需要全文检索的,是进行full text的全文检索,当然如果搜索的字段值做了not_analyzed,match query也相当于是term query了,比如下面这个搜索,由于在插入数据的时候我们没有对title这个字段进行规定,默认就是text类型的,会被自动分词,这样查询的时候只要title中包含了 hadoop,就可以匹配到,
GET /forum/article/_search
{
"query": {
"match": {
"title": "hadoop"
}
}
}
2、有些情况下,假如我们直接使用match进行查询,又希望查出来的结果尽可能是我们期望的包含更多关键词的结果,则在match进行匹配的时候可以添加其他的条件,以便提升结果的匹配精确度,
GET /forum/article/_search
{
"query": {
"match": {
"title": {
"query": "java hadoop",
"operator": "and"
}
}
}
}
这样匹配出来的结果包含了更多我们期望的关键词,即query中可以指定我们查询的结果中包含的关键词,
es还有其他的语法达到上述的效果,minimum_should_match ,通过这个语法,可以指定匹配的百分数,就是查询的关键词至少要达到的百分数,下面这个表示全部匹配,只查询到一条结果,
假如我们将百分数调低点,比如75%,可以看到查到两条结果,
3、当然,我们也可以将bool和match结合起来使用,如下,
GET /forum/article/_search
{
"query": {
"bool": {
"must": [
{"match": {"title": "java"}}
],
"must_not": [
{ "match": { "title": "spark"}}
]
, "should": [
{
"match": {
"title": "php"
}
}
]
}
}
}
通过这种方式,也可以达到更精准的匹配我们期望的查询结果,
简单总结来说,当我们使用match进行查询的时候,如果查询的field包含多个词,比如像下面这个,
{
"match": { "title": "java elasticsearch"}
}
其实es会在底层自动将这个match query转换为bool的语法bool should,指定多个搜索词,同时使用term query,则转化后的语法如下,
{
"bool": {
"should": [
{ "term": { "title": "java" }},
{ "term": { "title": "elasticsearch" }}
]
}
}
而上面所说的match中加and的查询,对应于bool查询,转化后为 term+must 的语法如下,
{
"match": {
"title": {
"query": "java elasticsearch",
"operator": "and"
}
}
}
{
"bool": {
"must": [
{ "term": { "title": "java" }},
{ "term": { "title": "elasticsearch" }}
]
}
}
对于minimum_should_match这种语法来说,道理类似,
{
"match": {
"title": {
"query": "java elasticsearch hadoop spark",
"minimum_should_match": "75%"
}
}
}
{
"bool": {
"should": [
{ "term": { "title": "java" }},
{ "term": { "title": "elasticsearch" }},
{ "term": { "title": "hadoop" }},
{ "term": { "title": "spark" }}
],
"minimum_should_match": 3
}
}
我们来看一个具体的操作实例,也就是说必须至少包含3个关键词的数据才会出现在搜索结果中,
3、在搜索中,我们有这样一种需求,期望搜索的结果中包含java 如果标题中包含hadoop或spark就优先搜索出来,同时呢,如果一个帖子包含java hadoop,一个帖子包含java spark,包含hadoop的帖子要比spark优先搜索出来,
对于这样的需求,通俗来讲,就是需要通过增大某些搜索条件的权重,从而在搜索的结果中,更多符合和满足我们业务场景的数据靠前搜索出来,在es中可以通过boost关键词来增加搜索条件的权重,
GET /forum/article/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "java"
}
}
],
"should": [
{
"match": {
"title": {
"query": "hadoop"
}
}
},
{
"match": {
"title": {
"query": "spark",
"boost":2
}
}
},
{
"match": {
"title": {
"query": "php"
}
}
},
{
"match": {
"title": {
"query": "hadoop",
"boost": 5
}
}
}
]
}
}
}
上面这个例子意思是我们赋予搜索的title中包含hadoop的条件权重更大,hadoop的结果会有限被搜索出来
4、dis_max语法,也叫best_field,在某些情况下,假如我们在bool查询中用多个字段进行查询,但是查询一样,就可能导致说查询出来的结果并不是按照我们期望的那个字段将其排在前面,也就是说,我们只需要包含指定字段的内容展示在前面,如下,
GET /forum/article/_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "java solution" }},
{ "match": { "content": "java solution" }}
]
}
}
}
title和content的搜索条件相同,但我们希望的是结果中title 包含java solution的靠前展示,但直接这样查询可能达不到预期的效果,如果使用dis_max进行拼接就可以了,
GET /forum/article/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "java solution" }},
{ "match": { "content": "java solution" }}
]
}
}
}
通过这样的方式,使得查询的结果更符合预期值,
5、但是使用dis_max,只取某一个query最大的分数,完全不考虑其他query的分数,即假如说某个结果中包title含了java,但topic中没有包含java,另一却是相反,还有的结果是两者都包含java,在dis_max语法下,只会拿到相关度得分最高的那一个,而不会考虑其他的结果,这时,如果需要获取其他的title或者topic包含java的结果,可以使用tie_breaker进一步包装,如下,
GET /forum/article/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "spark" }},
{ "match": { "topic": "java"}}
],
"tie_breaker": 0.6
}
}
}
这样查到3条结果,综合来说,最终还是需要结合实际业务场景进行使用,但是在大多数情况相爱,我们还是希望搜索的结果中是按照我们给定的条件包含更多的关键词的内容被优先搜索出来,
es使用与原理4 -- phrase match ,slop近似匹配,搜索推荐等等
match query,只能搜索到包含java和spark的document,但是不知道java和spark是不是离的很近
包含java或包含spark,或包含java和spark的doc,都会被返回回来。我们其实并不知道哪个doc,java和spark距离的比较近。如果我们就是希望搜索java spark,中间不能插入任何其他的字符 或者指定中间只能隔num个字符,那这个时候match去做全文检索,能搞定我们的需求吗?答案是,搞不定。
两个需求:
1、java spark,就靠在一起,中间不能插入任何其他字符,就要搜索出来这种doc
2、java spark,但是要求,java和spark两个单词靠的越近,doc的分数越高,排名越靠前
phrase match 就是短语匹配,将短语作为一个整体去查找。
3、分词后的临时 position
从结果中,我们可以看出 hello的临时位置是0,world, java spark 的位置依次是 1,2,3
4、短语搜索的原理(近似搜索的原理也是这样的)
hello world, java spark doc1
hi, spark java doc2
hello doc1(0)
wolrd doc1(1)
java doc1(2) doc2(2)
spark doc1(3) doc2(1)
java spark -- match phrase
java spark -- java和spark
java -- doc1(2) doc2(2)
spark -- doc1(3) doc2(1)
要找到每个term都在的一个共有的那些doc,就是要求一个doc,必须包含每个term,才能拿出来继续计算
doc1 -- java和spark -- spark position恰巧比java大1 -- java的position是2,spark的position是3,恰好满足条件 ,doc1符合条件
doc2 -- java和spark -- java position是2,spark position是1,spark position比java position小1,而不是大1 -- 光是position就不满足,那么doc2不匹配
类似的 近似搜索原理也是这样的
slop的含义是什么? 搜索文本,中的几个term,要经过几次移动才能与一个document匹配,这个移动的次数,就是slop。简单的说就是 java 和 spark之间的距离 或者java和spark交换后的距离+2(这里的2是交换所需要的步数),slop搜索下,关键词离的越近,relevance score就会越高。
比如你搜索一个java spark,含有java,或者含有是spark,或者同时含有,并且 尽可能让包含java spark,或者是java和spark离的很近的doc,排在最前面,同时提供了召回率还兼顾了精准率。
直接用match_phrase短语搜索,会导致必须有term都在doc field中出现,而且距离在slop限定范围内,才能匹配上
此时可以用bool组合match query和match_phrase query一起,来实现上述效果
match -- 只要简单的匹配到了一个term,就可以理解将term对应的doc作为结果返回,扫描倒排索引,扫描到了就ok
phrase match -- 首先扫描到所有term的doc list; 找到包含所有term的doc list; 然后对每个doc都计算每个term的position,是否符合指定的范围; slop,需要进行复杂的运算,来判断能否通过slop移动,匹配一个doc
match query的性能比phrase match和proximity match(有slop)要高很多。因为后两者都要计算position的距离。
match query比phrase match的性能要高10倍,比proximity match的性能要高20倍。
默认情况下,match也许匹配了1000个doc,proximity match全都需要对每个doc进行一遍运算,判断能否slop移动匹配上,然后去贡献自己的分数
但是很多情况下,match出来也许1000个doc,其实用户大部分情况下是分页查询的,所以可能最多只会看前几页,比如一页是10条,最多也许就看5页,就是50条
proximity match只要对前50个doc进行slop移动去匹配,去贡献自己的分数即可,不需要对全部1000个doc都去进行计算和贡献分数
match:1000个doc,其实这时候每个doc都有一个分数了; proximity match,前50个doc,进行rescore,重打分,即可; 让前50个doc,term举例越近的,排在越前面
1、前缀搜索
C3D0-KD345
C3K5-DFG65
C4I8-UI365
C3 -- 上面这两个都搜索出来 -- 根据字符串的前缀去搜索
不用帖子的案例背景,因为比较简单,直接用自己手动建的新索引,给大家演示一下就可以了
2、前缀搜索的原理
prefix query不计算relevance score,与prefix filter唯一的区别就是,filter会cache bitset
扫描整个倒排索引,举例说明
前缀越短,要处理的doc越多,性能越差,尽可能用长前缀搜索
前缀搜索,它是怎么执行的?性能为什么差呢?
match
C3-D0-KD345
C3-K5-DFG65
C4-I8-UI365
全文检索
每个字符串都需要被分词
c3 doc1,doc2
d0
kd345
k5
dfg65
c4
i8
ui365
c3 -- 扫描倒排索引 -- 一旦扫描到c3,就可以停了,因为带c3的就2个doc,已经找到了 -- 没有必要继续去搜索其他的term了
match性能往往是很高的
如果前缀搜索那么 (前缀搜索是不分词的)
C3-D0-KD345
C3-K5-DFG65
C4-I8-UI365
c3 -- 先扫描到了C3-D0-KD345,很棒,找到了一个前缀带c3的字符串 -- 还是要继续搜索的,因为后面还有一个C3-K5-DFG65,也许还有其他很多的前缀带c3的字符串 -- 你扫描到了一个前缀匹配的term,
不能停,必须继续搜索 -- 直到扫描完整个的倒排索引,才能结束,所以prefix性能很差
3、通配符搜索
跟前缀搜索类似,功能更加强大
C3D0-KD345
C3K5-DFG65
C4I8-UI365
5字符-D任意个字符5
5?-*5:通配符去表达更加复杂的模糊搜索的语义
?:任意字符
*:0个或任意多个字符
性能一样差,必须扫描整个倒排索引,才ok
4、正则搜索
C[0-9].+
[0-9]:指定范围内的数字
[a-z]:指定范围内的字母
.:一个字符
+:前面的正则表达式可以出现一次或多次
wildcard和regexp,与prefix原理一致,都会扫描整个索引,性能很差
输入 hello w ,会联想到hello world,hello we,hello win,hello wind 等等
原理跟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来实现
什么是ngram
quick,5种长度下的ngram
ngram length=1,q u i c k
ngram length=2,qu ui ic ck
ngram length=3,qui uic ick
ngram length=4,quic uick
ngram length=5,quick
什么是edge ngram
quick,首字母后进行ngram
q
qu
qui
quic
quick
-----------------------------------搜索推荐 未完。。。。。。。。。
关于es模糊java和es模糊查询语法的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。
发布于:2022-12-01,除非注明,否则均为
原创文章,转载请注明出处。