Changeset d7499ca in flexoentity for org


Ignore:
Timestamp:
11/24/25 15:17:00 (7 weeks ago)
Author:
Enrico Schwass <ennoausberlin@…>
Branches:
master
Children:
2fd0536
Parents:
376e21b
Message:

Signature support for Linux and MacOS added

Location:
org
Files:
2 added
1 moved

Legend:

Unmodified
Added
Removed
  • org/FlexoEntityTalk.org

    r376e21b rd7499ca  
    7171enthält, um möglichst eindeutig, aber nicht zu lang zu sein.
    7272
     73AF-I251022-70F759@001D
     74│  │ │       │     │ │
     75│  │ │       │     │ └── State (Draft, Approved, Signed, Published, Obsolete)
     76│  │ │       │     └──── Version
     77│  │ │       └────────── Hash (6 bytes, 12 Stellen)
     78│  │ └────────────────── Date (YYMMDD)
     79│  └──────────────────── Entity type (ITEM)
     80└─────────────────────── Domain (e.g. Air force)
     81
     82In der ersten Variante der FlexOID habe ich mich mit einem 6-stelligen Hash zufrieden gegeben,
     83weil das einfach lesbarer ist. Warum reicht das nicht?
     84
     85** Das Geburtstags-Paradoxon
     86
     87Der obige 3-Byte Hash liefert mir etwas über 16 Millionen unterschiedlich Varianten.
     88Das klingt viel. Ist es aber nicht. Wieviele Schüler müssen nacheinander die Klasse
     89betreten bis sich zwei finden, die mit mehr als 50 Prozent Wahrscheinlichkeit am gleichen
     90Tag Geburtstag (also ein identisches Merkmal) haben?
     91
     92** Lösung
     93
     94Ab 23 Schülern beträgt die Wahrscheinlichkeit 50 % (näherungsweise Wurzel 365 Tagen)
     95
     96Bei 47 Schülern beträgt die Wahrscheinlichkeit bereits 95 Prozent
     97
     98Unsere 3 Bytes ergeben zwar 16.000.000 mögliche Varianten - im Gegenzug zu den 365 Tagen im Jahr
     99aus dem Geburtstagsbeispiel - aber da die Wahrscheinlichkeit zur Kollision hier bei
     100etwa Wurzel 16 Mio. liegt, bekommt man bereits bei 4000 Neuzugängen die ersten
     101Übereinstimmungen im Hash.
     102
     103Der Hash ist also nicht gut genug, weil man sehr schnell und sehr häufig, diese
     104Übereinstimmungen feststellen und behandeln müsste, wenn man weiterhin eindeutige
     105Zuordnungen treffen will.
     106
     107Wenn man die Ausgabe der Hashfunktion auf 6 Bytes erweitert, kommen die ersten Kollisionen
     108erst bei etwa 20 Mio erzeugten Hashes (Fingerabdrücken) und die kann man dann ohne
     109Einbußen gesondert behandeln (Salzen), weil es so selten passiert.
     110
     111Übrigens, wenn man beim Menschen den Daumenabdruck nimmt und sich dabei auf 12 Merkmale
     112beschränkt und sehr lockere Toleranzen ansetzt (was man in der Praxis nicht macht),
     113hat man bereits nach 14000 Menschen eine Übereinstimmung. Bei 24 Merkmalen und sehr
     114lockeren Toleranzen, hat man bei etwa nach 9 Mio. Menschen eine ungefähre Übereinstimmung.
     115Da muss die Polizei schon sehr schlampig arbeiten, damit man fälschlicherweise beschuldigt wird.
     116Die Zahlen in der Realität sind sogar noch deutlich höher.
     117
     118** FlexoEntity
     119
     120Nun haben wir gesehen, dass wir mit der FlexOID (mit 6-Byte Hash) sehr viele unterschiedliche
     121Dinge eindeutig bestimmen können. Da unsere FlexOID erstmal nur eine Zeichenfolge ist,
     122brauchen wir etwas das damit umgehen kann und was dafür verantwortlich ist. Das ist die FlexoEntity.
     123
     124Sie beinhaltet zusätzlich ein Origin-Feld, wo festgehalten wird, woher diese
     125Entität stammt (beispielsweise aus einer Hashkollision oder einer Änderung an den weiteren Daten)
     126
     127Jede Klasse, die von FlexoEntity erbt, muss zwingend die Methode "text_seed" implementieren,
     128mit der der Algorithmus einer Hash-Funktion gefüttert wird, aus der dann der 6-Byte Hash herauspurzelt.
     129Hashfunktionen sind z.B. MD5, SHA1, SHA256 oder wie von mir genutzt: Blake2s.
     130Die Mathematik dahinter ist recht aufwändig, aber wer sich mal einlesen möchte
     131
     132- Hashing in Smalltalk: Theory and Practice von Andres Valloud
     133
     134Damit die Hash-Funktion genug Eingabedaten pro Entity hat, muss man sich überlegen, welche Merkmale
     135einer Entität man durch "text_seed" übermittelt.
     136
     137** text_seed
     138
     139Man kann beliebige Klassen von FlexoEntity ableiten und erhält ohne Aufwand die Funktionalität
     140zur eindeutigen Identifizierung und zur Lebenszyklus-Verwaltung
     141
     142Das ist das Beispiel einer ChoiceQuestion, also einer Testfrage, wo mögliche Antworten enthalten sind
     143
     144    @property
     145    def text_seed(self) -> str:
     146        """Include answer options (and points) for deterministic ID generation."""
     147        base = super().text_seed
     148        if not self.options:
     149            return base
     150
     151        joined = "|".join(
     152            f"{opt.text.strip()}:{opt.points}"
     153            for opt in sorted(self.options, key=lambda o: o.text.strip().lower())
     154        )
     155        return f"{base}::{joined}"
     156
     157** Lebenszyklus
     158
     159Der Lebenszyklus einer Entität folgt dieser Reihenfolge und ist nicht umkehrbar
     160
     161- Entwurf (DRAFT)
     162- Genehmigt (APPROVED)
     163- Unterschrieben (APPROVED_AND_SIGNED)
     164- Veröffentlicht (PUBLISHED)
     165- Veraltet (OBSOLETE)
     166
     167Eine Entität, die bereits die Stufe Veröffentlicht erreicht hat, kann nicht in die Stufe
     168(nur) Unterschrieben zurückkehren. Daher ist auch die Lebenszyklusstufe in der ID kodiert
     169(letztes Symbol der FlexOID)
     170
     171Beispiele für Entitäten:
     172
     173- Testfrage
     174- Fragenkatalog
     175- Einstufungstest
     176- Zertifikat
     177
     178Ein veröffentlichter Einstufungstest kann nur Fragen beinhalten, die ihrerseits die Stufe Veröffentlicht
     179erreicht haben. Ein Zertifikat kann nur ausgestellt werden, wenn der passende Einstufungstest die Stufe
     180Veröffentlicht hat. Das origin-Feld des Zertifikats sollte sinnvollerweise die ID des Tests enthalten.
     181
     182** Erhöhung der Versionsnummer oder neue ID
     183
     184Sobald - aus Gründen - eine neue ID vergeben werden muss, wird ggf. die Ursprungs-ID
     185im Feld origin der neuen FlexoEntity gespeichert. So ist immer ein Suchen im Stammbaum möglich.
     186
    73187AF-Q251022-70F759@001D
    74188│  │ │       │     │ │
     
    80194└─────────────────────── Domain (e.g. Air force)
    81195
    82 In der ersten Variante der FlexOID habe ich mich mit einem 6-stelligen Hash zufrieden gegeben,
    83 weil das einfach lesbarer ist. Warum reicht das nicht?
    84 
    85 ** Das Geburtstags-Paradoxon
    86 
    87 Der obige 3-Byte Hash liefert mir etwas über 16 Millionen unterschiedlich Varianten.
    88 Das klingt viel. Ist es aber nicht. Wieviele Schüler müssen nacheinander die Klasse
    89 betreten bis sich zwei finden, die mit mehr als 50 Prozent Wahrscheinlichkeit am gleichen
    90 Tag Geburtstag (also ein identisches Merkmal) haben?
    91 
    92 ** Lösung
    93 
    94 Ab 23 Schülern beträgt die Wahrscheinlichkeit 50 % (näherungsweise Wurzel 365 Tagen)
    95 
    96 Bei 47 Schülern beträgt die Wahrscheinlichkeit bereits 95 Prozent
    97 
    98 Unsere 3 Bytes ergeben zwar 16.000.000 mögliche Varianten - im Gegenzug zu den 365 Tagen im Jahr
    99 aus dem Geburtstagsbeispiel - aber da die Wahrscheinlichkeit zur Kollision hier bei
    100 etwa Wurzel 16 Mio. liegt, bekommt man bereits bei 4000 Neuzugängen die ersten
    101 Übereinstimmungen im Hash.
    102 
    103 Der Hash ist also nicht gut genug, weil man sehr schnell und sehr häufig, diese
    104 Übereinstimmungen feststellen und behandeln müsste, wenn man weiterhin eindeutige
    105 Zuordnungen treffen will.
    106 
    107 Wenn man die Ausgabe der Hashfunktion auf 6 Bytes erweitert, kommen die ersten Kollisionen
    108 erst bei etwa 20 Mio erzeugten Hashes (Fingerabdrücken) und die kann man dann ohne
    109 Einbußen gesondert behandeln (Salzen), weil es so selten passiert.
    110 
    111 Übrigens, wenn man beim Menschen den Daumenabdruck nimmt und sich dabei auf 12 Merkmale
    112 beschränkt und sehr lockere Toleranzen ansetzt (was man in der Praxis nicht macht),
    113 hat man bereits nach 14000 Menschen eine Übereinstimmung. Bei 24 Merkmalen und sehr
    114 lockeren Toleranzen, hat man bei etwa nach 9 Mio. Menschen eine ungefähre Übereinstimmung.
    115 Da muss die Polizei schon sehr schlampig arbeiten, damit man fälschlicherweise beschuldigt wird.
    116 Die Zahlen in der Realität sind sogar noch deutlich höher.
    117 
    118 ** FlexoEntity
    119 
    120 Nun haben wir gesehen, dass wir mit der FlexOID (mit 6-Byte Hash) sehr viele unterschiedliche
    121 Dinge eindeutig bestimmen können. Da unsere FlexOID erstmal nur eine Zeichenfolge ist,
    122 brauchen wir etwas das damit umgehen kann und was dafür verantwortlich ist. Das ist die FlexoEntity.
    123 
    124 Sie beinhaltet zusätzlich eine Signatur und ein Origin-Feld, wo festgehalten wird, woher diese
    125 Entität stammt (beispielsweise aus einer Hashkollision oder einer Änderung an den weiteren Daten)
    126 
    127 Jede Klasse, die von FlexoEntity erbt, muss zwingend die Method "text_seed" implementieren, mit der
    128 der Algorithmus einer Hash-Funktion gefüttert wird, aus der dann der 6-Byte Hash herauspurzelt.
    129 Hashfunktionen sind z.B. MD5, SHA1, SHA256 oder wie von mir genutzt Blake2s.
    130 Die Mathematik dahinter ist recht aufwändig, aber wer sich mal einlesen möchte
    131 
    132 - Hashing in Smalltalk: Theory and Practice von Andres Valloud
    133 
    134 Damit die Hash-Funktion genug Eingabedaten pro Entity hat, muss man sich überlegen, welche Merkmale
    135 einer Entität man durch "text_seed" übermittelt.
    136 
    137 ** text_seed
    138 
    139 Man kann beliebige Klassen von FlexoEntity ableiten und erhält ohne Aufwand die Funktionalität
    140 zur eindeutigen Identifizierung und zur Lebenszyklus-Verwaltung
    141 
    142 
    143 Das ist das Beispiel einer OptionQuestion, also einer Testfrage, wo mögliche Antworten enthalten sind
    144 
    145     @property
    146     def text_seed(self) -> str:
    147         """Include answer options (and points) for deterministic ID generation."""
    148         base = super().text_seed
    149         if not self.options:
    150             return base
    151 
    152         joined = "|".join(
    153             f"{opt.text.strip()}:{opt.points}"
    154             for opt in sorted(self.options, key=lambda o: o.text.strip().lower())
    155         )
    156         return f"{base}::{joined}"
    157 
    158 ** Lebenszyklus
    159 
    160 Der Lebenszyklus einer Entität folgt dieser Reihenfolge und ist nicht umkehrbar
    161 
    162 - Entwurf (DRAFT)
    163 - Genehmigt (APPROVED)
    164 - Unterschrieben (SIGNED)
    165 - Veröffentlicht (PUBLISHED)
    166 - Veraltet (OBSOLETE)
    167 
    168 Eine Entität, die bereits die Stufe Veröffentlicht erreicht hat, kann nicht in die Stufe
    169 (nur) Unterschrieben zurückkehren. Daher ist auch die Lebenszyklusstufe in der ID kodiert
    170 (letztes Symbol der FlexOID)
    171 
    172 Beispiele für Entitäten:
    173 
    174 - Testfrage
    175 - Fragenkatalog
    176 - Einstufungstest
    177 - Zertifikat
    178 
    179 Ein veröffentlichter Einstufungstest kann nur Fragen beinhalten, die ihrerseits die Stufe Veröffentlicht
    180 erreicht haben. Ein Zertifikat kann nur ausgestellt werden, wenn der passende Einstufungstest die Stufe
    181 Veröffentlicht hat. Das origin-Feld des Zertifikats sollte sinnvollerweise die ID des Tests enthalten.
    182 
    183 ** Erhöhung der Versionsnummer oder neue ID
    184 
    185 Sobald - aus Gründen - eine neue ID vergeben werden muss, wird ggf. die Ursprungs-ID
    186 im Feld origin der neuen FlexoEntity gespeichert. So ist immer ein Suchen im Stammbaum möglich.
    187 
    188 AF-Q251022-70F759@001D
    189 │  │ │       │     │ │
    190 │  │ │       │     │ └── State (Draft, Approved, Signed, Published, Obsolete)
    191 │  │ │       │     └──── Version
    192 │  │ │       └────────── Hash (3 bytes, 6 Stellen)
    193 │  │ └────────────────── Date (YYMMDD)
    194 │  └──────────────────── Entity type (Question)
    195 └─────────────────────── Domain (e.g. Air force)
    196 
    197196
    198197Eine einfache Erhöhung der Versionsnummer (am Ende der ID) ist unter Umständen auch ausreichend,
Note: See TracChangeset for help on using the changeset viewer.