美文网首页
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