美文网首页
elasticsearch6 dsl解析(1)

elasticsearch6 dsl解析(1)

作者: symop | 来源:发表于2019-01-01 13:24 被阅读0次

版本号:6.0.1

上两周,es从2升级到6,而我负责升级的东西,只有查询,写dsl写的快吐了,在这里吐槽下,mysql导入es的字段原汁原味的,字段都不转化的。如下图

mmp,然后只能自己做了字段转换,言归正传,写了那么多dsl,在想底层怎么解析,一直没时间,趁着元旦写一下,底层是lucene,从lucene先看起来,es6.0.1采用lucene的版本7.0.1,下载代码导入idea,这个可以谷歌。

Query中rewrite是重新构建语法数的方法,Query子类如下图

类没截全,太多了,其中MultiTermQuery( 抽象类)和BooleanQuery是常用的,MultiTermQuery子类如下

比如类似下面常遇到的查询

{

    "query": {

        "bool": {

            "must": [

                { "term": { "title": "Search" }},

               { "wildcard": { "content": "Elasticsearch*“}}

            ],

            "filter": [

                { "term": { "status": "published" }},

                { "range": { "publish_date": { "gte": "2019­01­01" }}}

            ]

        }

    }

}

BooleanQuery.rewrite方法太长,不上图了,其中有一段是这样的

重写rewrite方法,所以问题回到了只看常用的MultiTermQuery类,其它的暂时不解析,类太多了。MultiTermQuery提供了三种Query树重写的方法,第一种是CONSTANT_SCORE_REWRITE,第二种SCORING_BOOLEAN_REWRITE,第三种CONSTANT_SCORE_BOOLEAN_REWRITE。

第一种使得MultiTermQuery对应的大于16个的Term看成一个Term(小于16个的term转换成BooleanQuery and形式),组成一个docid set,作为统一的倒排表参与倒排表的合并,这样无论这样的Term在索引中有多少,都只会有一个倒排表参与合并,不会产生TooManyClauses异常,也使得性能得到提高。但是多个Term之间的tf, idf等差别将被忽略.

第二种使得整个Query对象树被展开,叶子节点都为TermQuery,MultiTermQuery中的多个Term可根据在索引中的tf, idf等参与打分计算(和第三种方式的区别在于第三种方式分数是个常量),然而我们事先并不知道索引中和MultiTermQuery相对应的Term到底有多少个,因而会出现TooManyClauses异常,也即一个BooleanQuery中的子查询太多。这样会造成要合并的倒排表非常多,从而影响性能。

我们常用的是第一种方式我们只是需要模糊搜索不需要打分,所以只分析第一种,第一种打分方式是在MultiTermQueryConstantScoreWrapper.rewrite

放个demo,如下

Directory dir1 =newDirectory();

RandomIndexWriter iw1 =new RandomIndexWriter(random(), dir1);

Document doc1 =new Document();

doc1.add(newTextField("field", "foo bar", Field.Store.NO));

iw1.addDocument(doc1);

IndexReader reader1 = iw1.getReader();

iw1.close();

Directory dir2 =newDirectory();

RandomIndexWriter iw2 =new RandomIndexWriter(random(), dir2);

Document doc2 =new Document();

doc2.add(newTextField("field", "foo baz", Field.Store.NO));

iw2.addDocument(doc2);

IndexReader reader2 = iw2.getReader();

iw2.close();

BooleanQuery.Builder query =new BooleanQuery.Builder(); // Query: +foo -ba*

query.add(new TermQuery(new Term("field", "foo")), BooleanClause.Occur.MUST);

WildcardQuery wildcardQuery =new WildcardQuery(new Term("field", "ba*"));

// wildcardQuery.setRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_REWRITE);

wildcardQuery.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_REWRITE);

query.add(wildcardQuery, BooleanClause.Occur.MUST_NOT);

MultiReader multireader =new MultiReader(reader1, reader2);

IndexSearcher searcher =newSearcher(multireader);

assertEquals(0, searcher.search(query.build(), 10).totalHits);

es.awaitTermination(1, TimeUnit.SECONDS);

multireader.close();

reader1.close();

reader2.close();

dir1.close();

dir2.close();


刚开始Query如图

执行foo没有变化,当执行到ba*的时候截图如下

会把*自动补全,然后转换成一个一个的term然后去取数据,至于如何取数据和补数据,后面再说,太复杂了,这只是其中很少的一小块,还有很长的路要走。

相关文章

网友评论

      本文标题:elasticsearch6 dsl解析(1)

      本文链接:https://www.haomeiwen.com/subject/jdhnlqtx.html