Clojure 从数据创建等级库

Clojure 从数据创建等级库,clojure,specifications,Clojure,Specifications,我正试图从数据中创建规范。我有非常复杂的数据结构-所有嵌套映射 {:contexts ({:importer.datamodel/global-id "01b4e69f86e5dd1d816e91da27edc08e", :importer.datamodel/type "province", :name "a1", :importer.datamodel/part-of "8cda1baed04b668a167d4ca28e3cef36"} {:importer.dat

我正试图从数据中创建规范。我有非常复杂的数据结构-所有嵌套映射

{:contexts
 ({:importer.datamodel/global-id "01b4e69f86e5dd1d816e91da27edc08e",
   :importer.datamodel/type "province",
   :name "a1",
   :importer.datamodel/part-of "8cda1baed04b668a167d4ca28e3cef36"}
  {:importer.datamodel/global-id "8cda1baed04b668a167d4ca28e3cef36",
   :importer.datamodel/type "country",
   :name "AAA"}
  {:importer.datamodel/global-id "c78e5478e19f2d7c1b02088e53e8d8a4",
   :importer.datamodel/type "location",
   :importer.datamodel/center ["36." "2."],
   :importer.datamodel/part-of "01b4e69f86e5dd1d816e91da27edc08e"}
  {:importer.datamodel/global-id "88844f94f79c75acfcb957bb41386149",
   :importer.datamodel/type "organisation",
   :name "C"}
  {:importer.datamodel/global-id "102e96468e5d13058ab85c734aa4a949",
   :importer.datamodel/type "organisation",
   :name "A"}),
 :datasources
 ({:importer.datamodel/global-id "Source;ACLED",
   :name "ACLED",
   :url "https://www.acleddata.com"}),
 :iois
 ({:importer.datamodel/global-id "item-set;ACLED",
   :importer.datamodel/type "event",
   :datasource "Source;ACLED",
   :features
   ({:importer.datamodel/global-id
     "c74257292f584502f9be02c98829d9fda532a492e7dd41e06c31bbccc76a7ba0",
     :date "1997-01-04",
     :fulltext
     {:importer.datamodel/global-id "df5c7d6d075df3a7719ebdd39c6d4c7f",
      :text "bla"},
     :location-meanings
     ({:importer.datamodel/global-id
       "e5611219971164a15f06e07228fb7b51",
       :location "8cda1baed04b668a167d4ca28e3cef36",
       :contexts (),
       :importer.datamodel/type "position"}
      {:importer.datamodel/global-id
       "af36461d27ec1d8d28fd7f4a70ab7ce2",
       :location "c78e5478e19f2d7c1b02088e53e8d8a4",
       :contexts (),
       :importer.datamodel/type "position"}),
     :interaction-name "Violence",
     :importer.datamodel/type "description",
     :has-contexts
     ({:context "102e96468e5d13058ab85c734aa4a949",
       :context-association-type "actor",
       :context-association-name "actor-1",
       :priority "none"}
      {:context "88844f94f79c75acfcb957bb41386149",
       :context-association-type "actor",
       :context-association-name "actor-2",
       :priority "none"}),
     :facts
     ({:importer.datamodel/global-id
       "c46802ce6dcf33ca02ce113ffd9a855e",
       :importer.datamodel/type "integer",
       :name "fatalities",
       :value "16"}),
     :attributes
     ({:name "description",
       :importer.datamodel/type "string",
       :value "Violence"})}),
   :attributes (),
   :ioi-slice "per-item"})}
什么工具可以为此类结构创建等级库? 我正在尝试使用此工具:

但它给了我这个:

(spec/def :importer.datamodel/data
  (clojure.spec.alpha/coll-of
   (clojure.spec.alpha/or
    :collection
    (clojure.spec.alpha/coll-of
     (clojure.spec.alpha/keys
      :req
      [:importer.datamodel/global-id]
      :opt
      [:importer.datamodel/center
       :importer.datamodel/part-of
       :importer.datamodel/type]
      :opt-un
      [:importer.datamodel/attributes
       :importer.datamodel/datasource
       :importer.datamodel/features
       :importer.datamodel/ioi-slice
       :importer.datamodel/name
       :importer.datamodel/url]))
    :simple
    clojure.core/keyword?)))
这不是完整的解决方案。。。 我使用
(sp/pprint规范(sp/inferspecs数据:importer.datamodel/data)
。。。
什么工具可以为这样的结构创建规范?

为什么不使用触发器创建历史记录表,该触发器在事务之前插入旧数据

像这样的,

CREATE TRIGGER SNAPSHOT_TRIGGER BEFORE
INSERT ON MY_TABLE REFERENCING NEW ROW MYNEWROW
FOR EACH ROW
BEGIN
 INSERT INTO "HISTORY_TABLE" VALUES(121,'','zzzz');
END;

(请检查语法)

为什么不使用在事务之前插入旧数据的触发器创建历史记录表呢

像这样的,

CREATE TRIGGER SNAPSHOT_TRIGGER BEFORE
INSERT ON MY_TABLE REFERENCING NEW ROW MYNEWROW
FOR EACH ROW
BEGIN
 INSERT INTO "HISTORY_TABLE" VALUES(121,'','zzzz');
END;

(请检查语法)

对于HANA 2 SPS 03,您可以使用系统版本表功能。
对于HANA,自动保留一个单独的旧记录版本表,可以独立于主表进行访问。

对于HANA 2 SPS 03,您可以使用系统版本表功能。 对于HANA,它会自动保留一个单独的旧记录版本表,可以独立于主表进行访问

我正在尝试使用此工具:

等级库提供程序没有提供所需的结果,因为您的数据是一个复杂的嵌套/递归结构。其中一些地图可能是最好的规范,但规范提供程序不会这样做;其文档中的一个警告是,没有试图推断多规格。

正确规范某些贴图的唯一方法是使用多规范。它们的规范将取决于它们的
:importer.datamodel/type

首先,让我们看一下顶级键(假设映射位于名为
data
的绑定中):

为最外层的贴图创建
s/keys
规范:

(s/def ::my-map
  (s/keys :req-un [::contexts ::datasources ::iois]))
这些键是不合格的,但我们必须使用合格的关键字w/
:req un
来规范它们。通过遍历嵌套结构并收集数据,我们可以使用REPL查看嵌套映射的形状及其与
:importer.datamodel/type
的关系:

(let [keysets (atom #{})]
  (clojure.walk/postwalk
    (fn [v]
      (when (map? v)
        (swap! keysets conj [(:importer.datamodel/type v) (keys v)]))
      v)
    data)
  @keysets)
=>
#{...
  ["organisation" (:importer.datamodel/global-id :importer.datamodel/type :name)]
  [nil (:context :context-association-type :context-association-name :priority)]
  ["description"
   (:importer.datamodel/global-id :date :fulltext :location-meanings
    :interaction-name :importer.datamodel/type :has-contexts :facts :attributes)]
  ["event" (:importer.datamodel/global-id :importer.datamodel/type :datasource :features :attributes :ioi-slice)]
 ...}
(即将推出的等级库alpha将使从该数据以编程方式定义等级库变得更加容易。)

多规格 我们可以看到有些地图形状没有importer.datamodel/type,但我们可以为有此功能的图形编写多个规范。首先定义一个在类型键上分派的多重方法:

(defmulti type-spec :importer.datamodel/type)
然后为每个
:importer.datamodel/type
值编写一个
defmethod
。以下是几个例子:

(defmethod type-spec :default [_] (s/keys))
(defmethod type-spec "organisation" [_]
  (s/keys :req [:importer.datamodel/global-id]
          :req-un [::name]))
(defmethod type-spec "description" [_]
  (s/keys :req [:importer.datamodel/global-id]
          :req-un [::date ::fulltext ::location-meanings ::interaction-name
                   ::has-contexts ::facts ::attributes]))
(defmethod type-spec "event" [_]
  (s/keys :req-un [::features]))
然后定义
s/multi-spec

(s/def ::datamodel
  (s/multi-spec type-spec :importer.datamodel/type))
现在,我们所遵循的任何映射
::datamodel
都将根据其
:importer.datamodel/type
值解析规范。我们可以将该规范指定给规范将用于符合地图的关键字,例如,最外层的一个键:

(s/def ::contexts (s/coll-of ::datamodel))
现在,如果您从我们在
:context
下指定的一个映射中删除所需的键,spec可以告诉您出了什么问题。例如,从
“组织”
地图中删除
:name
键:

(s/explain ::my-map data)
In: [:contexts 3]
val: #:importer.datamodel{:global-id "88844f94f79c75acfcb957bb41386149",
                          :type "organisation"}
fails spec: :playground.so/datamodel
at: [:contexts "organisation"]
predicate: (contains? % :name)
其他规格 对于没有
:importer.datamodel/type
的映射,您应该能够定义一个键规范。例如,嵌套的
:has contexts
键有一个没有
:importer.datamodel/type
的映射集合,但是如果我们可以假设它们都是类似的,我们可以编写这个规范:

(s/def ::has-contexts
  (s/coll-of (s/keys :req-un [::context ::context-association-type
                              ::context-association-name ::priority])))
:has contexts
位于我们已经在上面的多规范中介绍过的映射中,只需将规范注册到此键即可使规范符合其值。包含此规范的最外层密钥是
:iois
,因此我们也可以规范该密钥:

(s/def ::iois (s/coll-of ::datamodel))
现在,符合
:我的地图
规范的输入将自动覆盖更多数据

什么工具可以为此类结构创建等级库

正如您所看到的,为这个结构编写一个完整的规范是不平凡的,但也是可能的。我不知道有任何现有的工具可以自动推断出这个结构的完整的“正确”规范。它必须直觉地知道,
:importer.datamodel/type
是一个键,可以用来分派到不同的
s/keys
规范-它仍然会做出一个潜在的无效假设。我认为在这种情况下,工具辅助规范生成更现实、更实用

我正在尝试使用此工具:

等级库提供程序没有提供所需的结果,因为您的数据是一个复杂的嵌套/递归结构。其中一些地图可能是最好的规范,但规范提供程序不会这样做;其文档中的一个警告是,没有试图推断多规格。

正确规范某些贴图的唯一方法是使用多规范。它们的规范将取决于它们的
:importer.datamodel/type

首先,让我们看一下顶级键(假设映射位于名为
data
的绑定中):

为最外层的贴图创建
s/keys
规范:

(s/def ::my-map
  (s/keys :req-un [::contexts ::datasources ::iois]))
这些键是不合格的,但我们必须使用合格的关键字w/
:req un
来规范它们。通过遍历嵌套结构并收集数据,我们可以使用REPL查看嵌套映射的形状及其与
:importer.datamodel/type
的关系:

(let [keysets (atom #{})]
  (clojure.walk/postwalk
    (fn [v]
      (when (map? v)
        (swap! keysets conj [(:importer.datamodel/type v) (keys v)]))
      v)
    data)
  @keysets)
=>
#{...
  ["organisation" (:importer.datamodel/global-id :importer.datamodel/type :name)]
  [nil (:context :context-association-type :context-association-name :priority)]
  ["description"
   (:importer.datamodel/global-id :date :fulltext :location-meanings
    :interaction-name :importer.datamodel/type :has-contexts :facts :attributes)]
  ["event" (:importer.datamodel/global-id :importer.datamodel/type :datasource :features :attributes :ioi-slice)]
 ...}
(即将推出的等级库alpha将使从该数据以编程方式定义等级库变得更加容易。)

多规格 我们可以看到有些地图形状没有importer.datamodel/type
,但我们可以为有此功能的图形编写多个规范。首先定义一个在类型键上分派的多重方法:

(defmulti type-spec :importer.datamodel/type)
然后为每个
:importer.datamodel/type
值编写一个
defmethod
。以下是几个例子:

(defmethod type-spec :default [_] (s/keys))
(defmethod type-spec "organisation" [_]
  (s/keys :req [:importer.datamodel/global-id]
          :req-un [::name]))
(defmethod type-spec "description" [_]
  (s/keys :req [:importer.datamodel/global-id]
          :req-un [::date ::fulltext ::location-meanings ::interaction-name
                   ::has-contexts ::facts ::attributes]))
(defmethod type-spec "event" [_]
  (s/keys :req-un [::features]))
然后定义
s/multi-spec

(s/def ::datamodel
  (s/multi-spec type-spec :importer.datamodel/type))
现在,我们所遵循的任何映射
::datamodel
都将根据其
:importer.datamodel/type
值解析规范。我们可以将该规范指定给该规范将用于符合的关键字