当前位置: 首页 > 工具软件 > MetaModel > 使用案例 >

metamodel_Apache MetaModel –在各种数据存储中提供统一的数据访问

常俊侠
2023-12-01

metamodel

最近, Human InferenceApache软件基金会 (ASF)宣布捐赠并接受对MetaModel项目的孵化。 以前,MetaModel可以通过LGPL许可获得,并由Human Inference的产品开发进行管理,但是现在已移至ASF,获得了新的许可,社区和治理。 那么,这个项目的全部目的是什么?它有什么用?

MetaModel是一个Java库,旨在提供一个用于与任何数据存储进行交互的接口; 可以是关系数据库,NoSQL数据库,电子表格文件或其他文件格式。 通过交互,我们意味着探索元数据,查询和写入/更改存储中包含的数据。 当然,任何这样的抽象都会遗漏细节,因此存在过度概括和失去重要功能的风险。 您不希望将关系SQL数据库的功能简化为仅使用全表扫描( SELECT * FROM [table] ),例如查询。 另一方面,除了特定SQL Server品牌和版本之外,您也不想公开在其他任何数据存储上都无法使用的功能。 最后,您将希望利用现有的通用技能与数据进行交互,例如SQL。

处理元数据

那么,由MetaModel项目选择的数据存储抽象方法是什么? 该项目通过与SQL非常相似的Java接口(或可选地从String解析)公开了查询模型。 由于查询被定义为常规Java对象,因此可以轻松解释它,并且-根据底层技术-将选择实际执行查询的最佳策略。 这意味着MetaModel不仅提供接口,而且还提供接口。 它还包括一个完整的查询引擎,可以适合于处理查询中涉及的某些或所有任务。 对于关系JDBC数据库,查询执行的99%仍将在数据库的本机引擎中进行。 但是,使用MetaModel,您还可以在CSV文件或Excel电子表格上触发相同的查询,从而利用MetaModel的查询引擎正确地对数据进行切片和切块。 您根本不需要更改查询。

当然,这是假设元数据和数据存储的结构兼容的。 不同的数据存储区具有公开或推断其元数据的不同方式。 JDBC数据库通常通过JDBC元数据API公开其元数据。 CSV和Excel工作表等文件格式的定义不太明确; 他们通过读取文件的标题行来浏览元数据。 并且,作为一个极端的示例,有多个NoSQL数据库明确没有元数据。 MetaModel为您提供了以编程方式指定元数据或通过检查数据存储的前N条记录来推断元数据的选项。

MetaModel的最核心构造是DataContext接口,它表示数据存储并用于浏览和查询它。 另外,UpdateableDataContext子接口可用于可在其中执行数据更新的可写数据存储。 只要确保您具有DataContext实例,就可以使用基本的代码完成来或多或少地学习整个库。 以下是几个常见DataContext实现的示例以及如何实例化它们:

// a DataContext for a CSV file
UpdateableDataContext csv = new CsvDataContext(new File(“data.csv”));
// a DataContext for an Excel spreadsheet
UpdateableDataContext excel = new ExcelDataContext(new File(“spreadsheet.xlsx”));
// a DataContext for a JDBC database (can use either DataSource or Connection)
java.sql.DataSource dataSource = …
UpdateableDataContext jdbc = new JdbcDataContext(dataSource);
// a DataContext for an XML file (where metadata is automatically inferred)
DataContext xml = new XmlDomDataContext(new File(“data.xml”));
// a DataContext for connecting to Salesforce.com’s data web services
UpdateableDataContext salesforce =
new SalesforceDataContext(username, pw, securityToken);
// a in-memory DataContext for POJOs (useful for testing and mocking)
Person record1 = ...
Person record2 = ...
TableDataProvider tableDataProvider = new ObjectTableDataProvider(
“persons”, Person.class, Arrays.asList(record1, record2));
UpdateableDataContext pojos = new PojoDataContext(“schema”, tableDataProvider);

元数据对于MetaModel不仅对于探索数据结构,而且对于定义查询都很重要。 如果您只是在使用适当的元数据,则要付出很多努力来确保可以安全地执行查询。 因此,在查询之前,作为开发人员,您需要做的第一件事就是掌握元数据对象。 例如,如果您知道有一个名为ORDER_LINE的表,其中包含一个price列和一个order_id列,则查询该表所需的元数据可以以通常的硬编码方式进行解析(显然,只有在您知道数据存储时,该表才起作用):

DataContext dataContext = ... // the DataContext object represents the ‘connection’
Table orderLines = dataContext.getTableByQualifiedLabel(“ORDER_LINES”);
Column price = orderLines.getColumnByName(“price”); Column orderId = orderLines.getColumnByName(“order_id”);

但是,API还允许您基于发现动态获取元数据。 这对于希望向用户显示可用表,列等并让用户自己做出影响查询的选择的应用程序非常有用:

Schema[] schema = dataContext.getSchemas();
Table[] tables = schemas[0].getTables();
Column[] columns = tables[0].getColumns();

MetaModel的另一个重要方面是将元数据,查询和数据交互周围的其他实体视为对象。 MetaModel中的查询是一个常规Java对象,您可以在执行前对其进行操作和传递。 这使应用程序可以创建复杂的工作流,其中不同的代码段可以参与查询计划的构建和优化,而不必转向繁琐SQL字符串操作。 它也有助于类型安全,因为例如Query模型基于类型安全的构造(如列,表等),而不是模糊的String文字。

查询数据存储

因此,让我们看看MetaModel中的查询是什么样的。

您可以通过三种方式触发相同的查询:

1.从头开始编写:
这是传统的面向POJO的方式。 它很冗长,但是可以提供您想要的所有灵活性。

Query q = new Query();
q.select(SUM, price);
q.select(orderId);
q.from(orderLines);
q.groupBy(orderId);
q.setMaxRows(100);
DataSet dataSet = dataContext.executeQuery(q);

2. 使用流畅的Builder API:
添加了Builder API,以允许另一种类型安全的查询方式,但具有较少的冗长性。 同样,此API通过builder-pattern为开发人员提供了有关下一步在逻辑上填充查询的子句的指示。 当只有一个用于构建查询的组件时,这是定义查询的首选方式:

Query q = dataContext.query().from(orderLines)
.select(SUM, price).and(orderId)
.groupBy(orderId).maxRows(100).toQuery();
DataSet dataSet = dataContext.executeQuery(q);

3. 从字符串中解析它:
有时您可能想偷工减料,而退回到更传统SQL字符串方法。 MetaModel也可以解析来自纯字符串的查询,但是它具有类型安全性较低的风险,因为只能在运行时验证字符串查询。

Query q = dataContext.parseQuery(
“SELECT SUM(price), order_id FROM order_lines GROUP BY order_id LIMIT 100”);
DataSet dataSet = dataContext.executeQuery(q);

如您所见,这三种方法的最终结果都是一个DataSet,这是一种表示表格查询结果的对象类型。 无需过多介绍所有DataSet功能,您可以像这样简单地对其进行遍历:

Try {
while (dataSet.next()) {
Row row = dataSet.getRow();
System.out.println(row.toString());
}
} finally {
dataset.close();
}

更新数据存储

使用MetaModel执行更新是通过类似的类型安全和元数据驱动的方法执行的。 如上所述,并非所有数据存储都是可写的,这就是为什么您需要一个同时实现UpdateableDataContext接口的DataContext对象的原因。 鉴于此,让我们尝试在示例中更新订单数据:

dataContext.executeUpdate(new UpdateScript() {
@Override
public void run(UpdateCallback cb) {
// insert a new order line
cb.insertInto(orderLines).value(orderId, 123).value(price, 395).execute();
// update the price of orderlines where order_id = 122
cb.update(orderLines).where(orderId).eq(122).value(price, 295).execute();
}
});

请注意,UpdateScript是用于设置逻辑事务边界的构造。 根据基础数据技术,将应用适当的交易策略。 JDBC数据库将应用ACID事务,大多数文件格式将使用同步写入等。 最终结果是,您可以使用一种语法在所有数据存储中写入数据。

由于匿名内部类的存在,此处的语法不是特别漂亮。 显然,使用Java 8中的Closures可以改善这种情况。但是,如果您只想执行单个操作,则可以直接使用几个方便的预构建UpdateScript类:

dataContext.executeUpdate(
new InsertInto(orderLines).value(orderId, 123).value(price, 395));

此外,executeUpdate方法可用于创建和删除表以及删除记录。

添加对新数据存储的支持

最后,MetaModel的专家用户可能会问' 如果我要连接到[XYZ],该怎么办? '(其中XYZ是我们尚不支持的奇异数据存储)。 显然,我们希望MetaModel易于扩展; 这是使查询引擎可插入的部分原因。 您需要做的是构建自己的DataContext接口实现; 但是,如果您从头开始,那并不是一件容易的事。 因此,我们提供了具有许多扩展点的抽象实现。 这是演练:

  • 让您的类扩展抽象类QueryPostprocessDataContext 。 您将看到需要实现一些抽象方法:
    • getMainSchema()
      应该实现此方法以提供您的DataContext公开的架构模型。
    • materializeMainSchemaTable(Table,Column [],int)
      应该实现此方法以提供对特定表的全表扫描的等效功能。
  • 现在,您的DataContext可以正常工作了,您可以将MetaModel与您的奇异数据存储一起使用!
  • 但是,让我们对其进行优化! 尽管我们的DataContext现在可以完全正常运行,但是对于某些查询而言,它可能无法发挥出色的性能,因为MetaModel的查询引擎必须依赖materializeMainSchemaTable(...)方法作为处理几乎所有查询的源。 您可能还需要重写以下两种方法:
    • executeCountQuery(...)
      许多数据存储区都有一种确定特定表的记录数的简单方法。 由于这也是一种常见的查询类型,因此重写此方法通常会有所帮助。
    • materializeMainSchemaTable(Table,Column [],int,int)
      人们经常浏览页面中的表格数据(从记录编号X到Y)。 此方法的额外int参数使您可以优化查询方式,例如单页数据而不是整个表。
    • executeQuery(查询)
      如果要进行进一步的优化,请使用WHERE或GROUP BY子句,重写此方法。 但是请注意许多极端情况,因为Query参数是一种丰富的对象类型。 这里启发的好例子包括在源代码中找到的SalesforceDataContext类和MongoDbDataContext类。

最后的话

在本文中,我们介绍了MetaModel,它是一个提供对各种数据存储的访问的库,解释了如何处理元数据,如何查询存储以及如何执行更新。

将来,我们打算在Apache的新家中进一步开发MetaModel。 我们将为HBase,Cassandra和其他现代数据库添加更多内置的DataContext实现。 以及进一步扩展元数据可以使用的功能集。 我们正在研究的一些想法是关于嵌套结构(地图和列表,在许多NoSQL数据库中都可用)的更丰富的元数据,创建虚拟表的能力(类似于VIEW,但在客户端而不是服务器上得到了便利),支持将POJO映射到DataSet行,并将更多功能插入查询引擎。

Apache MetaModel目前正在The Apache Software Foundation进行孵化。 如果您对此项目感兴趣,请在Apache Incubator MetaModel页面上找到邮件列表,错误跟踪等。

翻译自: https://www.infoq.com/articles/apache-incubator-metamodel/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

metamodel

 类似资料: