создать спецификацию из данных - PullRequest
0 голосов
/ 06 февраля 2019

Я пытаюсь создать спецификацию только из данных.У меня очень сложная структура данных - все вложенные карты.

{: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"})}

Каким инструментом можно создать спецификацию для такой структуры?Я пытаюсь использовать этот инструмент: https://github.com/stathissideris/spec-provider

, но он дает мне это:

(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-specs (sp/infer-specs data :importer.datamodel/data) 'data 's) ... Какой инструментможно создать спецификацию для такой структуры?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

С HANA 2 SPS 03 вы можете использовать функцию системных версий таблиц .Для системных версий таблиц HANA автоматически сохраняет отдельную таблицу старых версий записей, к которой можно получить доступ независимо от основной таблицы.

0 голосов
/ 01 марта 2019

Я пытаюсь использовать этот инструмент: https://github.com/stathissideris/spec-provider

spec-провайдер не дает желаемого результата, потому что ваши данные представляют собой сложную вложенную / рекурсивную структуру.Некоторые из этих карт лучше всего подходят с multi-specs , но провайдер спецификаций этого не сделает;одно из предостережений в его документах гласит: Не делается попыток сделать вывод о мультиспецификации.

Единственный способ правильно указать некоторые из этих карт - использоватьспецификации их спецификации будут зависеть от их значения :importer.datamodel/type.

Сначала давайте посмотрим на ключи верхнего уровня (при условии, что карта находится в привязке с именем data):

(keys data) => (:contexts :datasources :iois)

Создайте 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)]
 ...}

(Предстоящая альфа-спецификация должна облегчить определениеСпецификации программно из этих данных.)

Multi-specs

Мы можем видеть, что есть некоторые формы карт, которые не имеют :importer.datamodel/type, но мы можем написать мультиспекуляции для нихчто делать.Сначала определите мультиметод для отправки с помощью клавиши типа:

(defmulti type-spec :importer.datamodel/type)

Затем запишите defmethod для каждого значения :importer.datamodel/type.Вот несколько примеров:

(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))

Теперь, если вы удалите требуемый ключ из одной из карт, которые мы специфицировали под :contexts, спецификация может сказать вам, что не так.Например, удаление ключа :name из карты "organisation":

(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 isна карте мы уже рассмотрели мультиспекуляцию выше, и простая регистрация спецификации для этого ключа приведет к тому, что спецификация будет соответствовать ее значениям.Самый внешний ключ, который содержит эту спецификацию, - :iois, поэтому мы можем также указать эту клавишу:

(s/def ::iois (s/coll-of ::datamodel))

Теперь соответствие ввода спецификации ::my-map автоматически охватит больше данных.

Каким инструментом можно создать спецификацию для такой структуры?

Как видите, написание полной спецификации для этой структуры нетривиально, но возможно.Я не знаю ни одного существующего инструмента, который мог бы автоматически вывести полную, «правильную» спецификацию для этой структуры.Было бы интуитивно понятно, что :importer.datamodel/type - это ключ, который можно использовать для отправки различных s/keys спецификаций, и он все равно будет делать потенциально неверное предположение.Я думаю, что инструментальная генерация спецификаций с поддержкой более реалистична и практична в этом случае.

0 голосов
/ 06 февраля 2019

Почему бы не создать таблицу истории, используя триггер, который вставляет старые данные непосредственно перед транзакцией.

Примерно так:

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;

(проверьте синтаксис)

...