【问题标题】:jooq extend existing dialect. Adopt MySQL dialect to apache Hive dialectjooq 扩展现有的方言。采用 MySQL 方言到 apache Hive 方言
【发布时间】:2013-03-01 03:45:53
【问题描述】:

我正在尝试使用 JOOQ 来查询 Hive。 Hive SQL 方言非常接近 MySQL 方言。 现在我遇到了这些问题:

  • Hive 支持 LIMIT N,它不支持 LIMIT N OFFSET K. Dummy 解决方案 - 覆盖 select.limit(limit);

在 JOOQ 中解决此类问题的最佳实践是什么?

【问题讨论】:

    标签: mysql hadoop hive cloudera jooq


    【解决方案1】:

    这是最肮脏的解决方案 :) 不幸的是,JOOQ 用户组没有回答 :(

    public class CountRatingQueryBuilder {
    
        private static final String SCORING_TABLE_NAME = "web_resource_rating";
    
        private final Connection connection;
        private final ScoringMetadata scoringMetadata;
    
        private final SelectSelectStep select;
        private final Factory create;
    
        public CountRatingQueryBuilder(Connection connection, ScoringMetadata scoringMetadata){
            this.connection = connection;
            this.scoringMetadata = scoringMetadata;
    
            create = new Factory(this.connection, SQLDialect.MYSQL);
            select = create.select();
    
            withSelectFieldsClause();
        }
    
        public CountRatingQueryBuilder withLimit(int limit){
            select.limit(limit);
            return this;
        }
    
        public CountRatingQueryBuilder withRegionId(Integer regionId){
            select.where(REGION_ID.field().equal(regionId));
            return this;
        }
    
        public CountRatingQueryBuilder withResourceTypeId(int resourceTypeId){
            select.where(RESOURCE_TYPE_ID.field().equal(resourceTypeId));
            return this;
        }
    
        public CountRatingQueryBuilder withRequestTimeBetween(long beginTimestamp, long endTimestamp){
            select.where(REQUEST_TIME.field().between(beginTimestamp, endTimestamp));
            return this;
        }
    
        public CountRatingQueryBuilder withResourceId(int resourceId){
            select.where(RESOURCE_ID.field().equal(resourceId));
            return this;
        }
    
    
    
        protected void withGroupByClause(){
            select.groupBy(REGION_ID.field());
            select.groupBy(RESOURCE_TYPE_ID.field());
            select.groupBy(RESOURCE_ID.field());
            select.groupBy(CONTENT_ID.field());
        }
    
        protected void withSelectFieldsClause(){
            select.select(REGION_ID.field());
            select.select(RESOURCE_TYPE_ID.field());
            select.select(CONTENT_ID.field());
            select.select(RESOURCE_ID.field());
            select.select(Factory.count(HIT_COUNT.field()).as(SUM_HIT_COUNT.fieldName()));
        }
    
        protected void withFromClause(){
            select.from(SCORING_TABLE_NAME);
        }
    
        protected void withOrderByClause(){
            select.orderBy(SUM_HIT_COUNT.field().desc());
        }
    
        public String build(){
            withGroupByClause();
            withOrderByClause();
            withFromClause();
            return select.getSQL().replace("offset ?","");//dirty hack for MySQL dialect. TODO: we can try to implement our own SQL dialect for Hive :)
    
        }
    
        public List<ResultRow> buildAndFetch(){
            String sqlWithPlaceholders = build();
    
            List<ResultRow> scoringResults = new ArrayList<ResultRow>(100);
            List<Record> recordResults = create.fetch(sqlWithPlaceholders, ArrayUtils.subarray(select.getBindValues().toArray(new Object[select.getBindValues().size()]),0, select.getBindValues().size()-1));//select.fetch();
            for(Record record : recordResults){
                ResultRowBuilder resultRowBuilder = ResultRowBuilder.create();
    
                resultRowBuilder.withContentType(scoringMetadata.getResourceType(record.getValue(RESOURCE_TYPE_ID.fieldName(), Integer.class)));
                resultRowBuilder.withHitCount(record.getValue(SUM_HIT_COUNT.fieldName(), Long.class));
                resultRowBuilder.withUrl(record.getValue(CONTENT_ID.fieldName(), String.class));
                scoringResults.add(resultRowBuilder.build());
            }
            return scoringResults;
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      不幸的是,扩展 jOOQ 以彻底支持新的 SQL 方言并不是很简单。 jOOQ 的 API 随着时间的推移变得越来越广泛,支持一组很棒的标准和特定于供应商的 SQL 语法变体。虽然 Apache Hive 方言可能看起来与 MySQL 相似,但可能有许多细微的差异需要在 jOOQ 的内部实现。 LIMIT .. OFFSET 子句的不同实现只是一个问题。也就是说,将 jOOQ 与“未知”或“不受支持”的方言一起使用通常不是一个好主意。

      解决方案:短期内

      在短期内,您可能需要修补 jOOQ 呈现的 SQL。最好的技术是使用此处记录的 ExecuteListener:

      收到“renderEnd()”事件后,您将能够访问呈现的 SQL 并使用正则表达式或您可能喜欢的任何技术对其进行修改。

      解决方案:从长远来看

      从长远来看,如果/何时实现#2337,可能会有更好的解决方案(但我们可能不会实现)

      【讨论】:

      • 嗨,我花了很多时间检查代码。不幸的是,没有“正常”的方式来贡献新的方言。我会寻找听众,我没有读到他们。谢谢。
      • jooq.org/doc/3.0/manual/sql-execution/execute-listeners 无效“最终类 DefaultConfiguration 实现配置”是包可见的,并且无法实例化它(仅在我的项目中创建相同的包)。我做错了什么?
      • 哎呀,你是对的。该构造函数不可见。应该是fixed
      • @Sergey:是的,由于 jOOQ 3.0 中的 API 更改,可能会出现一些类似的错误......再次感谢您的报告
      猜你喜欢
      • 2019-08-09
      • 2021-01-31
      • 2021-10-09
      • 1970-01-01
      • 2022-12-29
      • 2017-02-18
      • 2016-08-05
      • 2023-02-23
      • 2013-04-08
      相关资源
      最近更新 更多