Repository: apache/streampipes
Pull request #3265 (2024-09-30 07:21:51)

fix: Add spring boot to AllExtensionsIIoTInit
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  ~
  -->

  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/community/get-involved/
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar.
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->
This PR adds the `@SpringBootApplication` annotation to the `AllExtensionsIIoTInit` class to align it with other classes extending `StreamPipesExtensionsServiceBase`. This ensures consistency and expected behavior across all extension classes.

### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): no

PR introduces (a) deprecation(s): no



Patch:
diff --git a/pom.xml b/pom.xml
index 0eb677e528..c1285c0a95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,8 +47,8 @@
         <checker-qual.version>3.43.0</checker-qual.version>
         <commons-codec.version>1.17.0</commons-codec.version>
         <commons-collections.version>3.2.2</commons-collections.version>
-        <commons-compress.version>1.26.0</commons-compress.version>
-        <commons-io.version>2.16.1</commons-io.version>
+        <commons-compress.version>1.27.1</commons-compress.version>
+        <commons-io.version>2.17.0</commons-io.version>
         <commons-lang3.version>3.14.0</commons-lang3.version>
         <commons-logging.version>1.3.2</commons-logging.version>
         <commons-pool2.version>2.12.0</commons-pool2.version>
diff --git a/streampipes-client-go/streampipes/model/common.go b/streampipes-client-go/streampipes/model/common.go
index 0cb1d9631f..d5a81d684b 100644
--- a/streampipes-client-go/streampipes/model/common.go
+++ b/streampipes-client-go/streampipes/model/common.go
@@ -29,7 +29,7 @@ type EventProperty struct {
 	Label              string             `json:"label,omitempty"`
 	Description        string             `json:"description,omitempty"`
 	RuntimeName        string             `json:"runtimeName,omitempty"`
-	DomainProperties   []string           `json:"domainProperties,omitempty"`
+	SemanticType       string             `json:"semanticType,omitempty"`
 	PropertyScope      string             `json:"propertyScope,omitempty"`
 	RuntimeID          string             `json:"runtimeId,omitempty"`
 	RuntimeType        string             `json:"runtimeType"`
@@ -42,7 +42,7 @@ type EventProperties struct {
 	Label              string            `json:"label"`
 	Description        string            `json:"description"`
 	RuntimeName        string            `json:"runtimeName"`
-	DomainProperties   []string          `json:"domainProperties"`
+	SemanticType       string            `json:"semanticType"`
 	PropertyScope      string            `json:"propertyScope"`
 	RuntimeID          string            `json:"runtimeId"`
 	RuntimeType        string            `json:"runtimeType,omitempty"`
diff --git a/streampipes-client-python/poetry.lock b/streampipes-client-python/poetry.lock
index 6733fb7f97..904c11ed1b 100644
--- a/streampipes-client-python/poetry.lock
+++ b/streampipes-client-python/poetry.lock
@@ -623,43 +623,38 @@ toml = ["tomli"]
 
 [[package]]
 name = "cryptography"
-version = "42.0.5"
+version = "43.0.1"
 description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"},
-    {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"},
-    {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"},
-    {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"},
-    {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"},
-    {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"},
-    {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"},
-    {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"},
-    {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"},
-    {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"},
-    {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"},
-    {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"},
-    {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"},
-    {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"},
-    {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"},
-    {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"},
-    {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"},
-    {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"},
-    {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"},
-    {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"},
-    {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"},
-    {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"},
-    {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"},
-    {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"},
-    {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"},
-    {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"},
-    {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"},
-    {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"},
-    {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"},
-    {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"},
-    {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"},
-    {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"},
+    {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
+    {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
+    {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
+    {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
+    {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
+    {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
+    {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
+    {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
+    {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
+    {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
+    {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
+    {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
+    {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
+    {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
+    {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
+    {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
+    {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
+    {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
+    {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
+    {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
+    {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
+    {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
+    {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
+    {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
+    {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
+    {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
+    {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
 ]
 
 [package.dependencies]
@@ -672,7 +667,7 @@ nox = ["nox"]
 pep8test = ["check-sdist", "click", "mypy", "ruff"]
 sdist = ["build"]
 ssh = ["bcrypt (>=3.1.5)"]
-test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
 test-randomorder = ["pytest-randomly"]
 
 [[package]]
diff --git a/streampipes-client-python/streampipes/functions/utils/data_stream_generator.py b/streampipes-client-python/streampipes/functions/utils/data_stream_generator.py
index 6d042088f3..6587a2e53c 100644
--- a/streampipes-client-python/streampipes/functions/utils/data_stream_generator.py
+++ b/streampipes-client-python/streampipes/functions/utils/data_stream_generator.py
@@ -78,7 +78,7 @@ def create_data_stream(
             EventProperty(  # type: ignore
                 label="timestamp",
                 runtime_name="timestamp",
-                domain_properties=["http://schema.org/DateTime"],
+                semantic_type="http://schema.org/DateTime",
                 property_scope="HEADER_PROPERTY",
                 runtime_type="http://www.w3.org/2001/XMLSchema#long",
             )
diff --git a/streampipes-client-python/streampipes/model/common.py b/streampipes-client-python/streampipes/model/common.py
index 950bb7f066..afcac4beac 100644
--- a/streampipes-client-python/streampipes/model/common.py
+++ b/streampipes-client-python/streampipes/model/common.py
@@ -109,7 +109,7 @@ class EventProperty(BasicModel):
     label: Optional[StrictStr]
     description: Optional[StrictStr]
     runtime_name: StrictStr
-    domain_properties: Optional[List[StrictStr]] = Field(default_factory=list)
+    semantic_type: Optional[StrictStr]
     property_scope: Optional[StrictStr] = Field(default="MEASUREMENT_PROPERTY")
     runtime_id: Optional[StrictStr]
     runtime_type: StrictStr = Field(default="http://www.w3.org/2001/XMLSchema#string")
diff --git a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/PersistPipelineHandler.java b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/PersistPipelineHandler.java
index f385334d05..7a262fca26 100644
--- a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/PersistPipelineHandler.java
+++ b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/PersistPipelineHandler.java
@@ -29,9 +29,6 @@ import org.apache.streampipes.model.staticproperty.OneOfStaticProperty;
 import org.apache.streampipes.model.template.PipelineTemplateInvocation;
 import org.apache.streampipes.vocabulary.SO;
 
-import java.net.URI;
-import java.util.List;
-
 public class PersistPipelineHandler {
 
   private static final String templateId = "org.apache.streampipes.manager.template.instances.DataLakePipelineTemplate";
@@ -97,16 +94,13 @@ public class PersistPipelineHandler {
         .stream()
         .filter(ep -> ep instanceof EventPropertyPrimitive)
         .map(ep -> (EventPropertyPrimitive) ep)
-        .filter(ep -> hasTimestampType(ep.getDomainProperties()))
+        .filter(ep -> hasTimestampType(ep.getSemanticType()))
         .map(EventProperty::getRuntimeName)
         .findFirst()
         .orElseThrow(() -> new IllegalArgumentException("Could not find timestamp field in schema"));
   }
 
-  private boolean hasTimestampType(List<URI> semanticTypes) {
-    return semanticTypes
-        .stream()
-        .map(URI::toString)
-        .anyMatch(s -> s.equalsIgnoreCase(SO.DATE_TIME));
+  private boolean hasTimestampType(String semanticType) {
+    return SO.DATE_TIME.equalsIgnoreCase(semanticType);
   }
 }
diff --git a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/SchemaMetadataEnricher.java b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/SchemaMetadataEnricher.java
index 1650839226..bc2a2ffba0 100644
--- a/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/SchemaMetadataEnricher.java
+++ b/streampipes-connect-management/src/main/java/org/apache/streampipes/connect/management/compact/SchemaMetadataEnricher.java
@@ -24,9 +24,6 @@ import org.apache.streampipes.model.schema.EventPropertyPrimitive;
 import org.apache.streampipes.model.schema.PropertyScope;
 import org.apache.streampipes.vocabulary.XSD;
 
-import java.net.URI;
-import java.util.List;
-
 public class SchemaMetadataEnricher {
 
   public void enrich(EventProperty property,
@@ -41,7 +38,7 @@ public class SchemaMetadataEnricher {
       property.setDescription(propertyDef.description());
     }
     if (property instanceof EventPropertyPrimitive && propertyDef.semanticType() != null) {
-      property.setDomainProperties(List.of(URI.create(propertyDef.semanticType())));
+      property.setSemanticType(propertyDef.semanticType());
     }
   }
 
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
index a7ff90b45c..8e2381d506 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
@@ -125,7 +125,7 @@ public class ToOriginalSchemaConverter implements ITransformationRuleVisitor, Pr
   public void visit(TimestampTranfsformationRuleDescription rule) {
     var property = findPrimitiveProperty(properties, rule.getRuntimeKey());
     property.setRuntimeType(Datatypes.String.toString());
-    property.setDomainProperties(List.of());
+    property.setSemanticType(null);
   }
 
   @Override
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
index 92b1674d0d..8ea159406f 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
@@ -127,7 +127,7 @@ public class ToTransformedSchemaConverter implements ITransformationRuleVisitor,
     property.setPropertyScope(rule.getPropertyScope().name());
 
     if (Objects.nonNull(rule.getSemanticType())) {
-      property.setDomainProperties(List.of(URI.create(rule.getSemanticType())));
+      property.setSemanticType(rule.getSemanticType());
     }
     if (Objects.nonNull(rule.getMeasurementUnit())) {
       property.setMeasurementUnit(URI.create(rule.getMeasurementUnit()));
@@ -152,7 +152,7 @@ public class ToTransformedSchemaConverter implements ITransformationRuleVisitor,
   @Override
   public void visit(TimestampTranfsformationRuleDescription rule) {
     var property = findPrimitiveProperty(properties, rule.getRuntimeKey());
-    property.setDomainProperties(List.of(URI.create("http://schema.org/DateTime")));
+    property.setSemanticType("http://schema.org/DateTime");
     property.setRuntimeType(Datatypes.Long.toString());
     property.setPropertyScope(PropertyScope.HEADER_PROPERTY.toString());
     var metadata = property.getAdditionalMetadata();
diff --git a/streampipes-data-explorer-api/src/main/java/org/apache/streampipes/dataexplorer/api/IDataExplorerManager.java b/streampipes-data-explorer-api/src/main/java/org/apache/streampipes/dataexplorer/api/IDataExplorerManager.java
index ef1b68a0ca..586a77706c 100644
--- a/streampipes-data-explorer-api/src/main/java/org/apache/streampipes/dataexplorer/api/IDataExplorerManager.java
+++ b/streampipes-data-explorer-api/src/main/java/org/apache/streampipes/dataexplorer/api/IDataExplorerManager.java
@@ -34,15 +34,19 @@ public interface IDataExplorerManager {
    * @return An instance of {@link IDataLakeMeasurementCounter} configured to count the sizes of the specified measurements.
    */
   IDataLakeMeasurementCounter getMeasurementCounter(
-    List<DataLakeMeasure> allMeasurements,
-    List<String> measurementsToCount
+      List<DataLakeMeasure> allMeasurements,
+      List<String> measurementsToCount
   );
 
   IDataExplorerQueryManagement getQueryManagement(IDataExplorerSchemaManagement dataExplorerSchemaManagement);
 
   IDataExplorerSchemaManagement getSchemaManagement();
 
-  ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure);
+  default ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure) {
+    return getTimeseriesStorage(measure, false);
+  }
+
+  ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure, boolean ignoreDuplicates);
 
   IDataLakeMeasurementSanitizer getMeasurementSanitizer(IStreamPipesClient client, DataLakeMeasure measure);
 }
diff --git a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/DataExplorerManagerInflux.java b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/DataExplorerManagerInflux.java
index 1c25d5fbc5..869f314b1d 100644
--- a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/DataExplorerManagerInflux.java
+++ b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/DataExplorerManagerInflux.java
@@ -21,9 +21,9 @@ package org.apache.streampipes.dataexplorer.influx;
 import org.apache.streampipes.client.api.IStreamPipesClient;
 import org.apache.streampipes.commons.environment.Environments;
 import org.apache.streampipes.dataexplorer.DataExplorerSchemaManagement;
+import org.apache.streampipes.dataexplorer.api.IDataExplorerManager;
 import org.apache.streampipes.dataexplorer.api.IDataExplorerQueryManagement;
 import org.apache.streampipes.dataexplorer.api.IDataExplorerSchemaManagement;
-import org.apache.streampipes.dataexplorer.api.IDataExplorerManager;
 import org.apache.streampipes.dataexplorer.api.IDataLakeMeasurementCounter;
 import org.apache.streampipes.dataexplorer.api.IDataLakeMeasurementSanitizer;
 import org.apache.streampipes.dataexplorer.api.ITimeSeriesStorage;
@@ -38,28 +38,33 @@ public class DataExplorerManagerInflux implements IDataExplorerManager {
 
   @Override
   public IDataLakeMeasurementCounter getMeasurementCounter(
-    List<DataLakeMeasure> allMeasurements,
-    List<String> measurementsToCount) {
+      List<DataLakeMeasure> allMeasurements,
+      List<String> measurementsToCount) {
     return new DataLakeMeasurementCounterInflux(allMeasurements, measurementsToCount);
   }
 
   @Override
   public IDataExplorerQueryManagement getQueryManagement(
-    IDataExplorerSchemaManagement dataExplorerSchemaManagement
-    ) {
+      IDataExplorerSchemaManagement dataExplorerSchemaManagement
+  ) {
     return new DataExplorerQueryManagementInflux(dataExplorerSchemaManagement);
   }
 
   @Override
   public IDataExplorerSchemaManagement getSchemaManagement() {
     return new DataExplorerSchemaManagement(StorageDispatcher.INSTANCE
-                                                             .getNoSqlStore()
-                                                             .getDataLakeStorage());
+        .getNoSqlStore()
+        .getDataLakeStorage());
   }
 
   @Override
-  public ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure) {
-    return new TimeSeriesStorageInflux(measure, Environments.getEnvironment(), new InfluxClientProvider());
+  public ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure, boolean ignoreDuplicates) {
+    return new TimeSeriesStorageInflux(
+        measure,
+        ignoreDuplicates,
+        Environments.getEnvironment(),
+        new InfluxClientProvider()
+    );
   }
 
   @Override
diff --git a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilter.java b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilter.java
new file mode 100644
index 0000000000..fe70b15eae
--- /dev/null
+++ b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.dataexplorer.influx;
+
+import org.apache.streampipes.model.runtime.field.PrimitiveField;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class PropertyDuplicateFilter {
+
+  private final boolean ignoreDuplicates;
+  private final Map<String, Object> lastValues;
+
+  public PropertyDuplicateFilter(boolean ignoreDuplicates) {
+    this.ignoreDuplicates = ignoreDuplicates;
+    this.lastValues = new HashMap<>();
+  }
+
+  public boolean shouldIgnoreField(String sanitizedRuntimeName,
+                                   PrimitiveField eventPropertyPrimitiveField) {
+    var rawValue = eventPropertyPrimitiveField.getRawValue();
+    boolean shouldIgnore = ignoreDuplicates && lastValues.containsKey(sanitizedRuntimeName)
+        && Objects.equals(lastValues.get(sanitizedRuntimeName), rawValue);
+    lastValues.put(sanitizedRuntimeName, rawValue);
+    return shouldIgnore;
+  }
+}
diff --git a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyHandler.java b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyHandler.java
index 74d03ba3e2..a19c7d9ed8 100644
--- a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyHandler.java
+++ b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/PropertyHandler.java
@@ -34,10 +34,13 @@ public class PropertyHandler {
 
   private static final Logger LOG = LoggerFactory.getLogger(PropertyHandler.class);
 
-  private RawFieldSerializer rawFieldSerializer;
+  private final RawFieldSerializer rawFieldSerializer;
+  private final PropertyDuplicateFilter duplicateFilter;
 
-  public PropertyHandler() {
+
+  public PropertyHandler(PropertyDuplicateFilter duplicateFilter) {
     rawFieldSerializer = new RawFieldSerializer();
+    this.duplicateFilter = duplicateFilter;
   }
 
   /**
@@ -109,30 +112,32 @@ public class PropertyHandler {
       String sanitizedRuntimeName,
       PrimitiveField eventPropertyPrimitiveField
   ) {
-    // Store property according to property type
-    if (XSD.INTEGER.toString()
-                   .equals(runtimeType)) {
-      handleIntegerProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else if (XSD.LONG.toString()
-                       .equals(runtimeType)) {
-      handleLongProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else if (XSD.FLOAT.toString()
-                        .equals(runtimeType)) {
-      handleFloatProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else if (XSD.DOUBLE.toString()
-                         .equals(runtimeType)) {
-      handleDoubleProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else if (XSD.BOOLEAN.toString()
-                          .equals(runtimeType)) {
-      handleBooleanProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else if (SO.NUMBER.equals(runtimeType)) {
-      handleDoubleProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
-    } else {
-      handleStringProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+
+    if (!duplicateFilter.shouldIgnoreField(sanitizedRuntimeName, eventPropertyPrimitiveField)) {
+      // Store property according to property type
+      if (XSD.INTEGER.toString()
+          .equals(runtimeType)) {
+        handleIntegerProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else if (XSD.LONG.toString()
+          .equals(runtimeType)) {
+        handleLongProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else if (XSD.FLOAT.toString()
+          .equals(runtimeType)) {
+        handleFloatProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else if (XSD.DOUBLE.toString()
+          .equals(runtimeType)) {
+        handleDoubleProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else if (XSD.BOOLEAN.toString()
+          .equals(runtimeType)) {
+        handleBooleanProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else if (SO.NUMBER.equals(runtimeType)) {
+        handleDoubleProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      } else {
+        handleStringProperty(p, sanitizedRuntimeName, eventPropertyPrimitiveField);
+      }
     }
   }
 
-
   private void handleStringProperty(
       Point.Builder p,
       String sanitizedRuntimeName,
diff --git a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/TimeSeriesStorageInflux.java b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/TimeSeriesStorageInflux.java
index fa35cbe9b9..799808541e 100644
--- a/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/TimeSeriesStorageInflux.java
+++ b/streampipes-data-explorer-influx/src/main/java/org/apache/streampipes/dataexplorer/influx/TimeSeriesStorageInflux.java
@@ -38,15 +38,23 @@ public class TimeSeriesStorageInflux extends TimeSeriesStorage {
 
   private final PropertyHandler propertyHandler;
 
+  public TimeSeriesStorageInflux(
+      DataLakeMeasure measure,
+      Environment environment,
+      InfluxClientProvider influxClientProvider
+  ) throws SpRuntimeException {
+    this(measure, false, environment, influxClientProvider);
+  }
 
   public TimeSeriesStorageInflux(
       DataLakeMeasure measure,
+      boolean ignoreDuplicates,
       Environment environment,
       InfluxClientProvider influxClientProvider
   ) throws SpRuntimeException {
     super(measure);
     this.influxDb = influxClientProvider.getSetUpInfluxDBClient(environment);
-    propertyHandler = new PropertyHandler();
+    propertyHandler = new PropertyHandler(new PropertyDuplicateFilter(ignoreDuplicates));
   }
 
   protected void writeToTimeSeriesStorage(Event event) throws SpRuntimeException {
diff --git a/streampipes-data-explorer-iotdb/src/main/java/org/apache/streampipes/dataexplorer/iotdb/DataExplorerManagerIotDb.java b/streampipes-data-explorer-iotdb/src/main/java/org/apache/streampipes/dataexplorer/iotdb/DataExplorerManagerIotDb.java
index 97ef58e99e..612c2dee6c 100644
--- a/streampipes-data-explorer-iotdb/src/main/java/org/apache/streampipes/dataexplorer/iotdb/DataExplorerManagerIotDb.java
+++ b/streampipes-data-explorer-iotdb/src/main/java/org/apache/streampipes/dataexplorer/iotdb/DataExplorerManagerIotDb.java
@@ -56,7 +56,7 @@ public class DataExplorerManagerIotDb implements IDataExplorerManager {
   }
 
   @Override
-  public ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure) {
+  public ITimeSeriesStorage getTimeseriesStorage(DataLakeMeasure measure, boolean ignoreDuplicates) {
     return new TimeSeriesStorageIotDb(measure, new IotDbPropertyConverter(), new IotDbSessionProvider());
   }
 
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/ImageStoreUtils.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/ImageStoreUtils.java
index 59d4719a7d..c7e226c3ed 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/ImageStoreUtils.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/ImageStoreUtils.java
@@ -29,10 +29,7 @@ public class ImageStoreUtils {
 
   public static List<EventProperty> getImageProperties(DataLakeMeasure measure) {
     return measure.getEventSchema().getEventProperties().stream()
-        .filter(eventProperty -> eventProperty.getDomainProperties() != null
-            && !eventProperty.getDomainProperties()
-                             .isEmpty()
-            && eventProperty.getDomainProperties().get(0).toString().equals(SPSensor.IMAGE))
+        .filter(eventProperty -> SPSensor.IMAGE.equalsIgnoreCase(eventProperty.getSemanticType()))
         .collect(Collectors.toList());
   }
 }
diff --git a/streampipes-extensions-api/src/main/java/org/apache/streampipes/extensions/api/extractor/IParameterExtractor.java b/streampipes-extensions-api/src/main/java/org/apache/streampipes/extensions/api/extractor/IParameterExtractor.java
index 396f0f3961..2fd8e40f76 100644
--- a/streampipes-extensions-api/src/main/java/org/apache/streampipes/extensions/api/extractor/IParameterExtractor.java
+++ b/streampipes-extensions-api/src/main/java/org/apache/streampipes/extensions/api/extractor/IParameterExtractor.java
@@ -60,6 +60,8 @@ public interface IParameterExtractor {
 
   <V> List<V> selectedMultiValues(String internalName, Class<V> targetClass);
 
+  <V> List<V> selectedMultiValuesInternalNames(String internalName, Class<V> targetClass);
+
   <V> List<V> selectedTreeNodesInternalNames(String internalName,
                                              Class<V> targetClass);
 
@@ -102,4 +104,6 @@ public interface IParameterExtractor {
   List<String> getEventPropertiesSelectorByScope(PropertyScope scope);
 
   List<EventProperty> getEventPropertiesByScope(PropertyScope scope);
+
+  List<EventProperty> getInputEventProperties(int streamIndex);
 }
diff --git a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/parser/json/GeoJsonParser.java b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/parser/json/GeoJsonParser.java
index 0405a87ca2..f028ccfd12 100644
--- a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/parser/json/GeoJsonParser.java
+++ b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/adapter/parser/json/GeoJsonParser.java
@@ -23,7 +23,6 @@ import org.apache.streampipes.extensions.api.connect.IParserEventHandler;
 import org.apache.streampipes.extensions.management.connect.adapter.parser.util.JsonEventProperty;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
 import org.apache.streampipes.model.schema.EventProperty;
-import org.apache.streampipes.model.schema.EventPropertyPrimitive;
 import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
 import org.apache.streampipes.vocabulary.Geo;
 import org.apache.streampipes.vocabulary.SO;
@@ -41,9 +40,6 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -147,12 +143,8 @@ public class GeoJsonParser extends JsonParser {
 
   private EventProperty getEventPropertyGeoJson(String name, Object value, String domain) {
     EventProperty eventProperty = JsonEventProperty.getEventProperty(name, value);
-    try {
-      ((EventPropertyPrimitive) eventProperty).setDomainProperties(Arrays.asList(new URI(domain)));
+    eventProperty.setSemanticType(domain);
 
-    } catch (URISyntaxException e) {
-      LOG.error(e.getMessage());
-    }
     return eventProperty;
   }
 
diff --git a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/util/EventSchemaUtils.java b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/util/EventSchemaUtils.java
index f0a7020447..0f9a46b210 100644
--- a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/util/EventSchemaUtils.java
+++ b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/util/EventSchemaUtils.java
@@ -24,7 +24,6 @@ import org.apache.streampipes.model.schema.EventPropertyPrimitive;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.vocabulary.SO;
 
-import java.net.URI;
 import java.util.List;
 import java.util.Optional;
 
@@ -47,7 +46,7 @@ public class EventSchemaUtils {
 
   private static Optional<EventPropertyPrimitive> getTimstampProperty(List<EventProperty> eventProperties) {
     for (EventProperty ep : eventProperties) {
-      if (ep instanceof EventPropertyPrimitive && ep.getDomainProperties().contains(URI.create(SO.DATE_TIME))) {
+      if (ep instanceof EventPropertyPrimitive && SO.DATE_TIME.equalsIgnoreCase(ep.getSemanticType())) {
         return Optional.of((EventPropertyPrimitive) ep);
       }
 
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileReplayAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileReplayAdapter.java
index ed0d256605..a5a42a4c09 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileReplayAdapter.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/FileReplayAdapter.java
@@ -53,7 +53,6 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executors;
@@ -212,9 +211,7 @@ public class FileReplayAdapter implements StreamPipesAdapter {
         .getEventSchema()
         .getEventProperties()
         .stream()
-        .filter(eventProperty ->
-                    eventProperty.getDomainProperties()
-                                 .contains(URI.create(SO.DATE_TIME)))
+        .filter(eventProperty -> SO.DATE_TIME.equals(eventProperty.getSemanticType()))
         .findFirst();
 
     if (timestampField.isEmpty()) {
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpServerProtocol.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpServerProtocol.java
index 88a08a6d94..ed49af0e31 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpServerProtocol.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/protocol/stream/HttpServerProtocol.java
@@ -51,9 +51,7 @@ import org.apache.streampipes.sdk.utils.Datatypes;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
 import java.util.ArrayList;
-import java.util.Collections;
 
 public class HttpServerProtocol implements StreamPipesAdapter {
 
@@ -86,8 +84,7 @@ public class HttpServerProtocol implements StreamPipesAdapter {
     primitive.setRuntimeName(memberExtractor.singleValueParameter(EP_RUNTIME_NAME, String.class));
     primitive.setRuntimeType(extractRuntimeType(memberExtractor.selectedSingleValue(EP_RUNTIME_TYPE, String.class)));
     primitive
-        .setDomainProperties(Collections
-            .singletonList(URI.create(memberExtractor.singleValueParameter(EP_DOMAIN_PROPERTY, String.class))));
+        .setSemanticType(memberExtractor.singleValueParameter(EP_DOMAIN_PROPERTY, String.class));
     return primitive;
   }
 
diff --git a/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
index f0b49c1831..d35b598427 100644
--- a/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
+++ b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
@@ -48,6 +48,9 @@ import org.apache.streampipes.sinks.internal.jvm.InternalSinksExtensionModuleExp
 import org.apache.streampipes.sinks.notifications.jvm.NotificationsExtensionModuleExport;
 import org.apache.streampipes.wrapper.standalone.runtime.StandaloneStreamPipesRuntimeProvider;
 
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
 public class AllExtensionsIIoTInit extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
diff --git a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/listcollector/ListCollector.java b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/listcollector/ListCollector.java
index 6d908bd7dc..11cb6bfb98 100644
--- a/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/listcollector/ListCollector.java
+++ b/streampipes-extensions/streampipes-processors-filters-siddhi/src/main/java/org/apache/streampipes/processors/siddhi/listcollector/ListCollector.java
@@ -83,16 +83,16 @@ public class ListCollector extends StreamPipesSiddhiProcessor
     List<EventProperty> selectedProperty = extractor
         .getInputStreamEventPropertySubset(Collections.singletonList(propertySelector));
 
-    if (selectedProperty.size() > 0) {
+    if (!selectedProperty.isEmpty()) {
       EventPropertyPrimitive prop = (EventPropertyPrimitive) selectedProperty.get(0);
       String newPropertyName = prop.getRuntimeName() + "_list";
       String newDatatype = prop.getRuntimeType();
-      String newDomainProperty = prop.getDomainProperties().get(0).toString();
+      String newSemanticType = prop.getSemanticType();
 
       EventPropertyList ep = EpProperties.listEp(Labels.from("list", "", ""),
           newPropertyName,
           Datatypes.fromDatatypeString(newDatatype),
-          newDomainProperty);
+          newSemanticType);
 
       inputSchema.addEventProperty(ep);
     }
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessor.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessor.java
index 316aa9c375..fff8f8283d 100644
--- a/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessor.java
+++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/main/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessor.java
@@ -85,11 +85,7 @@ public class TransformToBooleanProcessor
     EventSchema eventSchema = new EventSchema();
     EventSchema oldEventSchema = processingElement.getInputStreams().get(0).getEventSchema();
     // Gotta remove the "s0::" in the beginning
-    Set<String> transformFields =
-        (parameterExtractor.mappingPropertyValues(TRANSFORM_FIELDS_ID))
-            .stream()
-            .map(s -> s.substring(4))
-            .collect(Collectors.toSet());
+    Set<String> transformFields = getTransformFieldNames(parameterExtractor);
 
     for (EventProperty eventProperty : oldEventSchema.getEventProperties()) {
       //TODO: Test, if eventProperty is a primitive type (string, number, ...)
@@ -122,13 +118,13 @@ public class TransformToBooleanProcessor
   @Override
   public void onEvent(Event inputEvent, SpOutputCollector collector) throws SpRuntimeException {
     for (String transformField : transformFields) {
-      AbstractField field = inputEvent.getFieldBySelector(transformField);
+      AbstractField<?> field = inputEvent.getFieldBySelector(transformField);
       // Is the field a primitive (and no list/nested field)?
       if (field.isPrimitive()) {
         // Yes. So remove the element and replace it with a boolean (if possible)
         inputEvent.removeFieldBySelector(transformField);
         try {
-          inputEvent.addField(transformField, toBoolean(field.getRawValue()));
+          inputEvent.addField(removeFieldPrefix(transformField), toBoolean(field.getRawValue()));
         } catch (SpRuntimeException e) {
           LOG.info(e.getMessage());
           return;
@@ -154,4 +150,15 @@ public class TransformToBooleanProcessor
       throw new SpRuntimeException("Value " + s + " not convertible to boolean");
     }
   }
+
+  private Set<String> getTransformFieldNames(ProcessingElementParameterExtractor extractor) {
+    return extractor.mappingPropertyValues(TRANSFORM_FIELDS_ID)
+        .stream()
+        .map(this::removeFieldPrefix)
+        .collect(Collectors.toSet());
+  }
+
+  private String removeFieldPrefix(String fieldName) {
+    return fieldName.substring(4);
+  }
 }
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/InternalSinksExtensionModuleExports.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/InternalSinksExtensionModuleExports.java
index 8dba55f9aa..72bcbcb7d1 100644
--- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/InternalSinksExtensionModuleExports.java
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/InternalSinksExtensionModuleExports.java
@@ -24,6 +24,7 @@ import org.apache.streampipes.extensions.api.migration.IModelMigrator;
 import org.apache.streampipes.extensions.api.pe.IStreamPipesPipelineElement;
 import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeSink;
 import org.apache.streampipes.sinks.internal.jvm.datalake.migrations.DataLakeSinkMigrationV1;
+import org.apache.streampipes.sinks.internal.jvm.datalake.migrations.DataLakeSinkMigrationV2;
 import org.apache.streampipes.sinks.internal.jvm.notification.InternalStreamPipesNotificationSink;
 
 import java.util.Collections;
@@ -45,6 +46,8 @@ public class InternalSinksExtensionModuleExports implements IExtensionModuleExpo
 
   @Override
   public List<IModelMigrator<?, ?>> migrators() {
-    return List.of(new DataLakeSinkMigrationV1());
+    return List.of(
+        new DataLakeSinkMigrationV1(),
+        new DataLakeSinkMigrationV2());
   }
 }
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeDimensionProvider.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeDimensionProvider.java
new file mode 100644
index 0000000000..17ed2b9c87
--- /dev/null
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeDimensionProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.sinks.internal.jvm.datalake;
+
+import org.apache.streampipes.model.schema.EventProperty;
+import org.apache.streampipes.model.schema.EventPropertyPrimitive;
+import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.model.staticproperty.Option;
+import org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty;
+import org.apache.streampipes.sdk.utils.Datatypes;
+import org.apache.streampipes.vocabulary.SO;
+
+import java.util.List;
+
+public class DataLakeDimensionProvider {
+
+  public void applyOptions(List<EventProperty> inputFields,
+                           RuntimeResolvableAnyStaticProperty staticProperty) {
+    var primitiveFields = getPrimitiveFields(inputFields);
+    primitiveFields
+        .forEach(field -> addFieldIfNotExists(field, staticProperty.getOptions()));
+    staticProperty.getOptions().removeIf(o -> !existsInFields(o, primitiveFields));
+  }
+
+  private List<EventPropertyPrimitive> getPrimitiveFields(List<EventProperty> inputFields) {
+    return inputFields
+        .stream()
+        .filter(field -> field instanceof EventPropertyPrimitive)
+        .filter(field -> satisfiesFilter((EventPropertyPrimitive) field))
+        .map(field -> (EventPropertyPrimitive) field)
+        .toList();
+  }
+
+  private boolean satisfiesFilter(EventPropertyPrimitive field) {
+    return !field.getRuntimeType().equals(Datatypes.Float.toString())
+        &&  !(SO.DATE_TIME.equalsIgnoreCase(field.getSemanticType()));
+  }
+
+  private void addFieldIfNotExists(EventPropertyPrimitive field,
+                                   List<Option> options) {
+    if (options.stream().noneMatch(o -> o.getName().equals(field.getRuntimeName()))) {
+      options.add(new Option(
+          field.getRuntimeName(),
+          PropertyScope.valueOf(field.getPropertyScope()) == PropertyScope.DIMENSION_PROPERTY)
+      );
+    }
+  }
+
+  private boolean existsInFields(Option o,
+                                 List<EventPropertyPrimitive> primitiveFields) {
+    return primitiveFields.stream().anyMatch(field -> field.getRuntimeName().equals(o.getName()));
+  }
+}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java
index ef88bbdcdc..5cdeae32a0 100644
--- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/DataLakeSink.java
@@ -22,14 +22,19 @@ import org.apache.streampipes.commons.environment.Environments;
 import org.apache.streampipes.commons.exceptions.SpRuntimeException;
 import org.apache.streampipes.dataexplorer.TimeSeriesStore;
 import org.apache.streampipes.dataexplorer.management.DataExplorerDispatcher;
+import org.apache.streampipes.extensions.api.extractor.IStaticPropertyExtractor;
 import org.apache.streampipes.extensions.api.pe.context.EventSinkRuntimeContext;
+import org.apache.streampipes.extensions.api.runtime.SupportsRuntimeConfig;
 import org.apache.streampipes.model.DataSinkType;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.datalake.DataLakeMeasureSchemaUpdateStrategy;
 import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.model.graph.DataSinkDescription;
 import org.apache.streampipes.model.runtime.Event;
+import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty;
+import org.apache.streampipes.model.staticproperty.StaticProperty;
 import org.apache.streampipes.sdk.builder.DataSinkBuilder;
 import org.apache.streampipes.sdk.builder.StreamRequirementsBuilder;
 import org.apache.streampipes.sdk.helpers.EpRequirements;
@@ -39,15 +44,21 @@ import org.apache.streampipes.sdk.helpers.Options;
 import org.apache.streampipes.wrapper.params.compat.SinkParams;
 import org.apache.streampipes.wrapper.standalone.StreamPipesDataSink;
 
-public class DataLakeSink extends StreamPipesDataSink {
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataLakeSink extends StreamPipesDataSink implements SupportsRuntimeConfig {
 
   private static final String DATABASE_MEASUREMENT_KEY = "db_measurement";
   private static final String TIMESTAMP_MAPPING_KEY = "timestamp_mapping";
   public static final String SCHEMA_UPDATE_KEY = "schema_update";
+  public static final String DIMENSIONS_KEY = "dimensions_selection";
+  public static final String IGNORE_DUPLICATES_KEY = "ignore_duplicates";
 
   public static final String SCHEMA_UPDATE_OPTION = "Update schema";
 
   public static final String EXTEND_EXISTING_SCHEMA_OPTION = "Extend existing schema";
+  private static final Logger LOG = LoggerFactory.getLogger(DataLakeSink.class);
 
   private TimeSeriesStore timeSeriesStore;
 
@@ -55,25 +66,26 @@ public class DataLakeSink extends StreamPipesDataSink {
   @Override
   public DataSinkDescription declareModel() {
     return DataSinkBuilder
-      .create("org.apache.streampipes.sinks.internal.jvm.datalake", 1)
-      .withLocales(Locales.EN)
-      .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
-      .category(DataSinkType.INTERNAL)
-      .requiredStream(StreamRequirementsBuilder
-                        .create()
-                        .requiredPropertyWithUnaryMapping(
-                          EpRequirements.timestampReq(),
-                          Labels.withId(TIMESTAMP_MAPPING_KEY),
-                          PropertyScope.NONE
-                        )
-                        .build())
-      .requiredTextParameter(Labels.withId(DATABASE_MEASUREMENT_KEY))
-      .requiredSingleValueSelection(
-        Labels.withId(SCHEMA_UPDATE_KEY),
-        Options.from(SCHEMA_UPDATE_OPTION, EXTEND_EXISTING_SCHEMA_OPTION)
-      )
-
-      .build();
+        .create("org.apache.streampipes.sinks.internal.jvm.datalake", 2)
+        .withLocales(Locales.EN)
+        .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
+        .category(DataSinkType.INTERNAL)
+        .requiredStream(StreamRequirementsBuilder
+            .create()
+            .requiredPropertyWithUnaryMapping(
+                EpRequirements.timestampReq(),
+                Labels.withId(TIMESTAMP_MAPPING_KEY),
+                PropertyScope.NONE
+            )
+            .build())
+        .requiredTextParameter(Labels.withId(DATABASE_MEASUREMENT_KEY))
+        .requiredSingleValueSelection(
+            Labels.withId(SCHEMA_UPDATE_KEY),
+            Options.from(SCHEMA_UPDATE_OPTION, EXTEND_EXISTING_SCHEMA_OPTION)
+        )
+        .requiredMultiValueSelectionFromContainer(Labels.withId(DIMENSIONS_KEY))
+        .requiredSlideToggle(Labels.withId(IGNORE_DUPLICATES_KEY), false)
+        .build();
   }
 
   @Override
@@ -81,9 +93,21 @@ public class DataLakeSink extends StreamPipesDataSink {
     var extractor = parameters.extractor();
     var timestampField = extractor.mappingPropertyValue(TIMESTAMP_MAPPING_KEY);
     var measureName = extractor.singleValueParameter(DATABASE_MEASUREMENT_KEY, String.class);
-    var eventSchema = parameters.getInputSchemaInfos()
-                                .get(0)
-                                .getEventSchema();
+    var dimensions = extractor.selectedMultiValues(DIMENSIONS_KEY, String.class);
+    var ignoreDuplicates = extractor.slideToggleValue(IGNORE_DUPLICATES_KEY);
+    var eventSchema = new EventSchema(parameters.getInputSchemaInfos()
+        .get(0)
+        .getEventSchema()
+        .getEventProperties()
+        .stream()
+        .peek(ep -> {
+          if (dimensions.contains(ep.getRuntimeName())) {
+            LOG.info("Using {} as dimension", ep.getRuntimeName());
+            ep.setPropertyScope(PropertyScope.DIMENSION_PROPERTY.name());
+          }
+        })
+        .toList()
+    );
 
 
     var measure = new DataLakeMeasure(measureName, timestampField, eventSchema);
@@ -101,7 +125,7 @@ public class DataLakeSink extends StreamPipesDataSink {
         .sanitizeAndRegister();
 
     this.timeSeriesStore = new TimeSeriesStore(
-        new DataExplorerDispatcher().getDataExplorerManager().getTimeseriesStorage(measure),
+        new DataExplorerDispatcher().getDataExplorerManager().getTimeseriesStorage(measure, ignoreDuplicates),
         measure,
         Environments.getEnvironment(),
         true
@@ -118,4 +142,13 @@ public class DataLakeSink extends StreamPipesDataSink {
   public void onDetach() throws SpRuntimeException {
     this.timeSeriesStore.close();
   }
+
+  @Override
+  public StaticProperty resolveConfiguration(String staticPropertyInternalName,
+                                             IStaticPropertyExtractor extractor) {
+    var staticProperty = extractor.getStaticPropertyByName(DIMENSIONS_KEY, RuntimeResolvableAnyStaticProperty.class);
+    var inputFields = extractor.getInputEventProperties(0);
+    new DataLakeDimensionProvider().applyOptions(inputFields, staticProperty);
+    return staticProperty;
+  }
 }
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2.java
new file mode 100644
index 0000000000..5a81ba4cd7
--- /dev/null
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.sinks.internal.jvm.datalake.migrations;
+
+import org.apache.streampipes.extensions.api.extractor.IDataSinkParameterExtractor;
+import org.apache.streampipes.extensions.api.migration.IDataSinkMigrator;
+import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceTagPrefix;
+import org.apache.streampipes.model.graph.DataSinkInvocation;
+import org.apache.streampipes.model.migration.MigrationResult;
+import org.apache.streampipes.model.migration.ModelMigratorConfig;
+import org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty;
+import org.apache.streampipes.model.staticproperty.SlideToggleStaticProperty;
+import org.apache.streampipes.sdk.helpers.Labels;
+import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeDimensionProvider;
+import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeSink;
+
+public class DataLakeSinkMigrationV2 implements IDataSinkMigrator {
+  @Override
+  public ModelMigratorConfig config() {
+    return new ModelMigratorConfig(
+        "org.apache.streampipes.sinks.internal.jvm.datalake",
+        SpServiceTagPrefix.DATA_SINK,
+        1,
+        2
+    );
+  }
+
+  @Override
+  public MigrationResult<DataSinkInvocation> migrate(DataSinkInvocation element,
+                                                     IDataSinkParameterExtractor extractor) throws RuntimeException {
+    addDimensionSelection(element);
+    addDuplicateToggle(element);
+    return MigrationResult.success(element);
+  }
+
+  private void addDimensionSelection(DataSinkInvocation element) {
+    var label = Labels.from(
+        DataLakeSink.DIMENSIONS_KEY,
+        "Dimensions",
+        "Selected fields will be stored as dimensions."
+    );
+    var staticProperty = new RuntimeResolvableAnyStaticProperty(
+        label.getInternalId(),
+        label.getLabel(),
+        label.getDescription()
+    );
+    var inputFields = element.getInputStreams().get(0).getEventSchema().getEventProperties();
+    new DataLakeDimensionProvider().applyOptions(inputFields, staticProperty);
+
+    element.getStaticProperties().add(staticProperty);
+  }
+
+  private void addDuplicateToggle(DataSinkInvocation element) {
+    var label = Labels.from(
+        DataLakeSink.IGNORE_DUPLICATES_KEY,
+        "Ignore duplicates",
+        "Fields having the same value than the previous event are not stored."
+    );
+    var staticProperty = new SlideToggleStaticProperty(
+        label.getInternalId(),
+        label.getLabel(),
+        label.getDescription(),
+        false);
+
+    element.getStaticProperties().add(staticProperty);
+  }
+}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/documentation.md b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/documentation.md
index 2d58b7e3d9..b9dde8e06d 100644
--- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/documentation.md
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/documentation.md
@@ -41,6 +41,16 @@ This sink requires an event that provides a timestamp value (a field that is mar
 
 ## Configuration
 
+### Dimensions
+
+The fields which will be stored as dimensional values in the time series storage. Dimensions are typically identifiers 
+such as the ID of a sensor.
+Dimensions support grouping in the data explorer, but will be converted to a text-based field and provide less advanced 
+filtering capabilities.
+
+Be careful when modifying dimensions of existing pipelines! This might have impact on how you are able to view data in 
+the data explorer due to schema incompatibilities.
+
 ### Identifier
 
 The name of the measurement (table) where the events are stored.
@@ -60,3 +70,22 @@ The Schema Update Options dictate the behavior when encountering a measurement (
 - **Description:** Keeps old event fields in the event schema.
 - **Strategy:** This follows an append-only strategy, allowing continued work with historic data.
 - **Consideration:** Old properties may exist for which no new data is generated.
+
+
+### Dimensions
+
+Select fields which will be marked as dimensions. Dimensions reflect tags in the underlying time-series database. 
+Dimensions support grouping operations and can be used for fields with a limited set of values, e.g., boolean flags or 
+fields representing IDs. Dimensions are not a good choice for fields with a high number of different values since they 
+slow down database queries.
+
+By default, all fields which are marked as dimensions in the metadata are chosen and can be manually overridden 
+with this configuration.
+
+Data types which can be marked as dimensional values are booleans, integer, and strings.
+
+### Ignore Duplicates
+
+Before writing an event to the time series storage, a duplicate check is performed. By activating this option, only 
+fields having a different value than the previous event are stored. 
+This setting only affects measurement fields, not dimensions.
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/strings.en b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/strings.en
index 0b604bdfd9..d1fcc39c7e 100644
--- a/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/strings.en
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/main/resources/org.apache.streampipes.sinks.internal.jvm.datalake/strings.en
@@ -26,3 +26,9 @@ timestamp_mapping.description=The value which contains a timestamp
 
 schema_update.title=Schema Update
 schema_update.description=Update existing schemas with the new one or extend the existing schema with new properties
+
+dimensions_selection.title=Dimensions
+dimensions_selection.description=Selected fields will be stored as dimensions.
+
+ignore_duplicates.title=Ignore duplicates
+ignore_duplicates.description=Fields having the same value than the previous event are not stored. This only affects measurements, not tags.
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultType.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultType.java
index 225a899533..225fe1180d 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultType.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/matching/MatchingResultType.java
@@ -22,8 +22,8 @@ public enum MatchingResultType {
 
   DATATYPE_MATCH("Datatype Match", "A required datatype is not present in the input event property."),
   STREAM_MATCH("Stream Match", ""),
-  DOMAIN_PROPERTY_MATCH("Domain Property Match",
-      "A required domain property is not present in the input event property."),
+  SEMANTIC_TYPE_MATCH("Semantic Type Match",
+      "A required semantic type is not present in the input event property."),
   FORMAT_MATCH("Format Match", "No supported transport format found."),
   GROUNDING_MATCH("Grounding Match", ""),
   PROTOCOL_MATCH("Protocol Match", "No supported communication protocol found."),
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventProperty.java b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventProperty.java
index 2bfc4ce28d..ceddacc02b 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventProperty.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventProperty.java
@@ -19,15 +19,11 @@
 package org.apache.streampipes.model.schema;
 
 import org.apache.streampipes.model.util.ElementIdGenerator;
-import org.apache.streampipes.model.util.ListUtils;
 
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-import java.net.URI;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -45,15 +41,13 @@ public abstract class EventProperty {
   private String label;
   private String description;
   private String runtimeName;
-  private List<URI> domainProperties;
+  private String semanticType;
   private String propertyScope;
   private String runtimeId;
   private Map<String, Object> additionalMetadata;
 
-
   public EventProperty() {
     this.elementId = ElementIdGenerator.makeElementId(EventProperty.class);
-    this.domainProperties = new ArrayList<>();
     this.additionalMetadata = new HashMap<>();
   }
 
@@ -62,21 +56,16 @@ public abstract class EventProperty {
     this.label = other.getLabel();
     this.description = other.getDescription();
     this.runtimeName = other.getRuntimeName();
-    this.domainProperties = other.getDomainProperties();
     this.propertyScope = other.getPropertyScope();
     this.runtimeId = other.getRuntimeId();
     this.additionalMetadata = other.getAdditionalMetadata();
+    this.semanticType = other.getSemanticType();
   }
 
-  public EventProperty(List<URI> subClassOf) {
-    this();
-    this.domainProperties = subClassOf;
-  }
-
-  public EventProperty(String propertyName, List<URI> subClassOf) {
+  public EventProperty(String propertyName, String semanticType) {
     this();
     this.runtimeName = propertyName;
-    this.domainProperties = subClassOf;
+    this.semanticType = semanticType;
   }
 
   public EventProperty(String propertyName) {
@@ -97,14 +86,6 @@ public abstract class EventProperty {
     this.runtimeName = propertyName;
   }
 
-  public List<URI> getDomainProperties() {
-    return domainProperties;
-  }
-
-  public void setDomainProperties(List<URI> subClassOf) {
-    this.domainProperties = subClassOf;
-  }
-
   public String getLabel() {
     return label;
   }
@@ -153,9 +134,17 @@ public abstract class EventProperty {
     this.additionalMetadata = additionalMetadata;
   }
 
+  public String getSemanticType() {
+    return semanticType;
+  }
+
+  public void setSemanticType(String semanticType) {
+    this.semanticType = semanticType;
+  }
+
   @Override
   public int hashCode() {
-    return Objects.hash(elementId, label, description, runtimeName, domainProperties, propertyScope,
+    return Objects.hash(elementId, label, description, runtimeName, semanticType, propertyScope,
         runtimeId);
   }
 
@@ -174,7 +163,7 @@ public abstract class EventProperty {
            && Objects.equals(runtimeName, that.runtimeName)
            && Objects.equals(propertyScope, that.propertyScope)
            && Objects.equals(runtimeId, that.runtimeId)
-           && ListUtils.isEqualList(this.domainProperties, that.domainProperties);
+           && Objects.equals(semanticType, that.semanticType);
   }
 
   @Override
@@ -184,7 +173,7 @@ public abstract class EventProperty {
            + ", label='" + label + '\''
            + ", description='" + description + '\''
            + ", runtimeName='" + runtimeName + '\''
-           + ", domainProperties=" + domainProperties
+           + ", semanticType=" + semanticType
            + ", propertyScope='" + propertyScope + '\''
            + ", runtimeId='" + runtimeId + '\''
            + '}';
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyList.java b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyList.java
index 799a6ee568..98af25f1d1 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyList.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyList.java
@@ -20,8 +20,6 @@ package org.apache.streampipes.model.schema;
 
 import org.apache.streampipes.model.util.Cloner;
 
-import java.net.URI;
-import java.util.List;
 import java.util.Objects;
 
 public class EventPropertyList extends EventProperty {
@@ -51,10 +49,9 @@ public class EventPropertyList extends EventProperty {
     this.eventProperty = listProperty;
   }
 
-  public EventPropertyList(String propertyName, EventProperty eventProperty, List<URI> domainProperties) {
-    super(propertyName);
+  public EventPropertyList(String propertyName, EventProperty eventProperty, String semanticType) {
+    super(propertyName, semanticType);
     this.eventProperty = eventProperty;
-    this.setDomainProperties(domainProperties);
   }
 
   public EventProperty getEventProperty() {
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyPrimitive.java b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyPrimitive.java
index e1fa7d40cb..0822c163a4 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyPrimitive.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/schema/EventPropertyPrimitive.java
@@ -21,7 +21,6 @@ package org.apache.streampipes.model.schema;
 import org.apache.streampipes.model.util.Cloner;
 
 import java.net.URI;
-import java.util.List;
 import java.util.Objects;
 
 public class EventPropertyPrimitive extends EventProperty {
@@ -44,13 +43,11 @@ public class EventPropertyPrimitive extends EventProperty {
     }
   }
 
-  public EventPropertyPrimitive(List<URI> subClassOf) {
-    super(subClassOf);
-  }
-
-  public EventPropertyPrimitive(String runtimeType, String runtimeName,
-                                String measurementUnit, List<URI> subClassOf) {
-    super(runtimeName, subClassOf);
+  public EventPropertyPrimitive(String runtimeType,
+                                String runtimeName,
+                                String measurementUnit,
+                                String semanticType) {
+    super(runtimeName, semanticType);
     this.runtimeType = runtimeType;
     //this.measurementUnit = measurementUnit;
   }
@@ -92,8 +89,8 @@ public class EventPropertyPrimitive extends EventProperty {
     }
     EventPropertyPrimitive that = (EventPropertyPrimitive) o;
     return Objects.equals(runtimeType, that.runtimeType)
-           && Objects.equals(measurementUnit, that.measurementUnit)
-           && Objects.equals(valueSpecification, that.valueSpecification);
+        && Objects.equals(measurementUnit, that.measurementUnit)
+        && Objects.equals(valueSpecification, that.valueSpecification);
   }
 
   @Override
@@ -104,9 +101,9 @@ public class EventPropertyPrimitive extends EventProperty {
   @Override
   public String toString() {
     return "EventPropertyPrimitive{"
-           + "runtimeType='" + runtimeType + '\''
-           + ", measurementUnit=" + measurementUnit
-           + ", valueSpecification=" + valueSpecification
-           + '}';
+        + "runtimeType='" + runtimeType + '\''
+        + ", measurementUnit=" + measurementUnit
+        + ", valueSpecification=" + valueSpecification
+        + '}';
   }
 }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/PropertyDuplicateRemover.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/PropertyDuplicateRemover.java
index 4106f664da..90a0fdbcc8 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/PropertyDuplicateRemover.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/PropertyDuplicateRemover.java
@@ -43,29 +43,25 @@ public class PropertyDuplicateRemover {
       int i = 1;
       EventProperty newProperty = p;
       while (isAlreadyDefined(existingProperties, newProperty)) {
-        if (newProperty instanceof EventPropertyPrimitive) {
-          EventPropertyPrimitive primitive = (EventPropertyPrimitive) newProperty;
+        if (newProperty instanceof EventPropertyPrimitive primitive) {
           newProperty = new EventPropertyPrimitive(primitive.getRuntimeType(), primitive.getRuntimeName() + i, "",
-              primitive.getDomainProperties());
+              primitive.getSemanticType());
         }
-        if (newProperty instanceof EventPropertyNested) {
-          EventPropertyNested nested = (EventPropertyNested) newProperty;
+        if (newProperty instanceof EventPropertyNested nested) {
 
           //TODO: hack
           List<EventProperty> nestedProperties = new ArrayList<>();
 
           for (EventProperty np : nested.getEventProperties()) {
-            if (np instanceof EventPropertyPrimitive) {
-              EventPropertyPrimitive thisPrimitive = (EventPropertyPrimitive) np;
+            if (np instanceof EventPropertyPrimitive thisPrimitive) {
               EventProperty newNested =
                   new EventPropertyPrimitive(thisPrimitive.getRuntimeType(), thisPrimitive.getRuntimeName(), "",
-                      thisPrimitive.getDomainProperties());
+                      thisPrimitive.getSemanticType());
               nestedProperties.add(newNested);
             }
 
           }
           newProperty = new EventPropertyNested(nested.getRuntimeName() + i, nestedProperties);
-          //newProperty = new EventPropertyNested(nested.getPropertyName() +i, nested.getEventProperties());
         }
         i++;
       }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/TransformOutputSchemaGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/TransformOutputSchemaGenerator.java
index 656d10a4a7..902df7dc7d 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/TransformOutputSchemaGenerator.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/TransformOutputSchemaGenerator.java
@@ -36,7 +36,6 @@ import org.apache.streampipes.model.util.Cloner;
 import org.apache.streampipes.sdk.helpers.Tuple2;
 
 import java.net.URI;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -158,7 +157,7 @@ public class TransformOutputSchemaGenerator extends OutputSchemaGenerator<Transf
       }
 
     } else if (transformOperationType == TransformOperationType.DOMAIN_PROPERTY_TRANSFORMATION) {
-      eventProperty.setDomainProperties(Collections.singletonList(URI.create(value)));
+      eventProperty.setSemanticType(value);
 
     } else if (transformOperationType == TransformOperationType.RUNTIME_NAME_TRANSFORMATION) {
       eventProperty.setRuntimeName(value);
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatch.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatch.java
index a27f1350cd..6f9f121e2e 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatch.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatch.java
@@ -30,14 +30,14 @@ public class ListPropertyMatch implements Matcher<EventPropertyList, EventProper
     if (requirement.getEventProperty() == null) {
       return true;
     } else {
-      return domainPropertyMatch(offer, requirement, errorLog) && listItemMatch(offer, requirement,
+      return semanticTypeMatch(offer, requirement, errorLog) && listItemMatch(offer, requirement,
           errorLog);
     }
   }
 
-  private boolean domainPropertyMatch(EventPropertyList offer, EventPropertyList requirement,
+  private boolean semanticTypeMatch(EventPropertyList offer, EventPropertyList requirement,
                                       List<MatchingResultMessage> errorLog) {
-    return new DomainPropertyMatch().match(offer.getDomainProperties(), requirement.getDomainProperties(),
+    return new SemanticTypeMatch().match(offer.getSemanticType(), requirement.getSemanticType(),
         errorLog);
   }
 
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PrimitivePropertyMatch.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PrimitivePropertyMatch.java
index 82fa379c96..45124c0a57 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PrimitivePropertyMatch.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PrimitivePropertyMatch.java
@@ -38,16 +38,16 @@ public class PrimitivePropertyMatch extends AbstractMatcher<EventPropertyPrimiti
 
     boolean matchesUnit = unitMatch(offer.getMeasurementUnit(), requirement.getMeasurementUnit(), errorLog);
     boolean matchesDatatype = datatypeMatch(offer.getRuntimeType(), requirement.getRuntimeType(), errorLog);
-    boolean matchesDomainProperty = domainPropertyMatch(offer.getDomainProperties(), requirement.getDomainProperties
-        (), errorLog);
+    boolean matchesSemanticType = semanticTypeMatch(offer.getSemanticType(), requirement.getSemanticType(), errorLog);
 
     return MatchingUtils.nullCheck(offer, requirement)
-        || (matchesUnit && matchesDatatype && matchesDomainProperty);
+        || (matchesUnit && matchesDatatype && matchesSemanticType);
   }
 
-  private boolean domainPropertyMatch(List<URI> offer,
-                                      List<URI> requirement, List<MatchingResultMessage> errorLog) {
-    return new DomainPropertyMatch().match(offer, requirement, errorLog);
+  private boolean semanticTypeMatch(String offer,
+                                    String requirement,
+                                    List<MatchingResultMessage> errorLog) {
+    return new SemanticTypeMatch().match(offer, requirement, errorLog);
   }
 
   private boolean datatypeMatch(String offer, String requirement,
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PropertyMatch.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PropertyMatch.java
index ebbd28561e..ed0d4ec13f 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PropertyMatch.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/PropertyMatch.java
@@ -59,7 +59,7 @@ public class PropertyMatch extends AbstractMatcher<EventProperty, EventProperty>
 
   private boolean isAnyProperty(EventProperty eventProperty) {
     return eventProperty instanceof EventPropertyPrimitive
-        && eventProperty.getDomainProperties() == null
+        && eventProperty.getSemanticType() == null
         && ((EventPropertyPrimitive) eventProperty).getMeasurementUnit() == null
         && ((EventPropertyPrimitive) eventProperty).getRuntimeType() == null;
   }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/DomainPropertyMatch.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/SemanticTypeMatch.java
similarity index 62%
rename from streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/DomainPropertyMatch.java
rename to streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/SemanticTypeMatch.java
index ce2518d2e2..d748e9fc63 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/DomainPropertyMatch.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/v2/SemanticTypeMatch.java
@@ -22,22 +22,21 @@ import org.apache.streampipes.manager.matching.v2.utils.MatchingUtils;
 import org.apache.streampipes.model.client.matching.MatchingResultMessage;
 import org.apache.streampipes.model.client.matching.MatchingResultType;
 
-import java.net.URI;
 import java.util.List;
+import java.util.Objects;
 
-public class DomainPropertyMatch extends AbstractMatcher<List<URI>, List<URI>> {
+public class SemanticTypeMatch extends AbstractMatcher<String, String> {
 
-  public DomainPropertyMatch() {
-    super(MatchingResultType.DOMAIN_PROPERTY_MATCH);
+  public SemanticTypeMatch() {
+    super(MatchingResultType.SEMANTIC_TYPE_MATCH);
   }
 
   @Override
-  public boolean match(List<URI> offer, List<URI> requirement, List<MatchingResultMessage> errorLog) {
-    if (offer == null && ((requirement != null) && requirement.size() > 0)) {
+  public boolean match(String offer, String requirement, List<MatchingResultMessage> errorLog) {
+    if (offer == null && (requirement != null)) {
       return false;
     }
-    boolean match = MatchingUtils.nullCheck(offer, requirement)
-        || requirement.stream().allMatch(req -> offer.stream().anyMatch(of -> req.toString().equals(of.toString())));
+    boolean match = MatchingUtils.nullCheck(offer, requirement) || requirement.equalsIgnoreCase(offer);
 
     if (!match) {
       buildErrorMessage(errorLog, buildText(requirement));
@@ -45,12 +44,8 @@ public class DomainPropertyMatch extends AbstractMatcher<List<URI>, List<URI>> {
     return match;
   }
 
-  private String buildText(List<URI> requirement) {
-    if (requirement == null || requirement.size() == 0) {
-      return "-";
-    } else {
-      return requirement.get(0).toString();
-    }
+  private String buildText(String requirement) {
+    return Objects.requireNonNullElse(requirement, "-");
   }
 
 }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/remote/ContainerProvidedOptionsHandler.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/remote/ContainerProvidedOptionsHandler.java
index 16acbba678..eb212bb33e 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/remote/ContainerProvidedOptionsHandler.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/remote/ContainerProvidedOptionsHandler.java
@@ -30,6 +30,7 @@ import com.google.gson.JsonSyntaxException;
 import org.apache.http.client.fluent.Response;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 public class ContainerProvidedOptionsHandler {
 
@@ -49,7 +50,7 @@ public class ContainerProvidedOptionsHandler {
   }
 
   private RuntimeOptionsResponse handleResponse(Response httpResp) throws JsonSyntaxException, IOException {
-    String resp = httpResp.returnContent().asString();
+    String resp = httpResp.returnContent().asString(StandardCharsets.UTF_8);
     return JacksonSerializer.getObjectMapper().readValue(resp, RuntimeOptionsResponse.class);
   }
 
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
index 006f3f955d..c5ff418e82 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/PipelineElementFile.java
@@ -23,6 +23,7 @@ import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.rest.security.AuthConstants;
 import org.apache.streampipes.rest.shared.exception.SpMessageException;
+import org.apache.streampipes.sdk.helpers.Filetypes;
 
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -72,6 +73,13 @@ public class PipelineElementFile extends AbstractAuthGuardedRestResource {
               fileDetail.getInputStream()
           );
       return ok(metadata);
+    } catch (IllegalArgumentException e) {
+      return badRequest(Notifications.error(
+          String.format(
+              "This file type is not supported. Allowed file types are %s.",
+              Filetypes.getAllFileExtensions().toString()
+          )
+      ));
     } catch (Exception e) {
       return fail();
     }
@@ -132,10 +140,10 @@ public class PipelineElementFile extends AbstractAuthGuardedRestResource {
   @PreAuthorize(AuthConstants.HAS_READ_FILE_PRIVILEGE)
   public ResponseEntity<List<String>> getAllOriginalFilenames() {
     return ok(fileManager.getAllFiles()
-                         .stream()
-                         .map(fileMetadata -> fileMetadata.getFilename()
-                                                          .toLowerCase())
-                         .toList());
+        .stream()
+        .map(fileMetadata -> fileMetadata.getFilename()
+            .toLowerCase())
+        .toList());
   }
 
   @GetMapping(
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java
index 2ad5f735e5..1793698efb 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/StaticProperties.java
@@ -19,6 +19,7 @@
 package org.apache.streampipes.sdk;
 
 import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.model.staticproperty.AnyStaticProperty;
 import org.apache.streampipes.model.staticproperty.CodeInputStaticProperty;
 import org.apache.streampipes.model.staticproperty.CollectionStaticProperty;
 import org.apache.streampipes.model.staticproperty.FileStaticProperty;
@@ -97,9 +98,9 @@ public class StaticProperties {
    * @return A configured FreeTextStaticProperty instance.
    */
   public static FreeTextStaticProperty stringFreeTextProperty(
-          Label label,
-          boolean isMultiLine,
-          boolean arePlaceholdersSupported) {
+      Label label,
+      boolean isMultiLine,
+      boolean arePlaceholdersSupported) {
     var property = stringFreeTextProperty(label);
     property.setMultiLine(isMultiLine);
     property.setPlaceholdersSupported(arePlaceholdersSupported);
@@ -233,6 +234,17 @@ public class StaticProperties {
     return osp;
   }
 
+  public static AnyStaticProperty multiValueSelection(Label label, List<Option> options) {
+    var osp = new AnyStaticProperty(
+        label.getInternalId(),
+        label.getLabel(),
+        label.getDescription()
+    );
+    osp.setOptions(options);
+
+    return osp;
+  }
+
   public static SecretStaticProperty secretValue(Label label) {
     return new SecretStaticProperty(label.getInternalId(),
         label.getLabel(), label.getDescription());
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PrimitivePropertyBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PrimitivePropertyBuilder.java
index cdfaea0395..d313fe301d 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PrimitivePropertyBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PrimitivePropertyBuilder.java
@@ -25,7 +25,6 @@ import org.apache.streampipes.model.schema.QuantitativeValue;
 import org.apache.streampipes.sdk.utils.Datatypes;
 
 import java.net.URI;
-import java.util.Collections;
 import java.util.List;
 
 public class PrimitivePropertyBuilder {
@@ -53,12 +52,26 @@ public class PrimitivePropertyBuilder {
   /**
    * Specifies the semantics of the property (e.g., whether a double value stands for a latitude coordinate).
    *
-   * @param domainProperty The domain property as a String. The domain property should reflect an URI. Use some
+   * @param semanticType The semantic type as a String. Use some
    *                       existing vocabulary from {@link org.apache.streampipes.vocabulary} or create your own.
-   * @return
+   * @return PrimitivePropertyBuilder
+   */
+  public PrimitivePropertyBuilder semanticType(String semanticType) {
+    this.eventProperty.setSemanticType(semanticType);
+    return this;
+  }
+
+  /**
+   * @deprecated use {@link PrimitivePropertyBuilder#semanticType(String)} instead.
+   * Specifies the semantics of the property (e.g., whether a double value stands for a latitude coordinate).
+   *
+   * @param semanticType The semantic type as a String. Use some
+   *                       existing vocabulary from {@link org.apache.streampipes.vocabulary} or create your own.
+   * @return PrimitivePropertyBuilder
    */
-  public PrimitivePropertyBuilder domainProperty(String domainProperty) {
-    this.eventProperty.setDomainProperties(Collections.singletonList(URI.create(domainProperty)));
+  @Deprecated(forRemoval = true, since = "0.97.0")
+  public PrimitivePropertyBuilder domainProperty(String semanticType) {
+    this.eventProperty.setSemanticType(semanticType);
     return this;
   }
 
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PropertyRequirementsBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PropertyRequirementsBuilder.java
index fed9a70db4..eecb6fbec0 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PropertyRequirementsBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/PropertyRequirementsBuilder.java
@@ -22,8 +22,6 @@ import org.apache.streampipes.sdk.utils.Datatypes;
 import org.apache.streampipes.vocabulary.StreamPipes;
 
 import java.net.URI;
-import java.util.Arrays;
-import java.util.stream.Collectors;
 
 public class PropertyRequirementsBuilder {
 
@@ -57,15 +55,6 @@ public class PropertyRequirementsBuilder {
     return this;
   }
 
-  public PropertyRequirementsBuilder domainPropertyReq(String... domainProperties) {
-    this.propertyReq.setDomainProperties(Arrays
-        .stream(domainProperties)
-        .map(URI::create)
-        .collect(Collectors.toList()));
-
-    return this;
-  }
-
   public PropertyRequirementsBuilder measurementUnitReq(String measurementUnit) {
     this.propertyReq.setMeasurementUnit(URI.create(measurementUnit));
     return this;
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
index b7230510f3..844f26af2c 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/extractor/AbstractParameterExtractor.java
@@ -62,7 +62,7 @@ public abstract class AbstractParameterExtractor<T extends InvocableStreamPipesE
     implements IParameterExtractor {
 
   protected T sepaElement;
-  private TypeParser typeParser;
+  private final TypeParser typeParser;
 
   public AbstractParameterExtractor(T sepaElement) {
     this.sepaElement = sepaElement;
@@ -246,6 +246,17 @@ public abstract class AbstractParameterExtractor<T extends InvocableStreamPipesE
         .collect(Collectors.toList());
   }
 
+  @Override
+  public <V> List<V> selectedMultiValuesInternalNames(String internalName, Class<V> targetClass) {
+    return getStaticPropertyByName(internalName, AnyStaticProperty.class)
+        .getOptions()
+        .stream()
+        .filter(Option::isSelected)
+        .map(Option::getInternalName)
+        .map(o -> typeParser.parse(o, targetClass))
+        .collect(Collectors.toList());
+  }
+
   @Override
   /**
    * Extracts the user configuration from the tree static property.
@@ -666,4 +677,13 @@ public abstract class AbstractParameterExtractor<T extends InvocableStreamPipesE
                                                        .equals(scope.name()))
         .collect(Collectors.toList());
   }
+
+  @Override
+  public List<EventProperty> getInputEventProperties(int streamIndex) {
+    if (!sepaElement.getInputStreams().isEmpty()) {
+      return sepaElement.getInputStreams().get(streamIndex).getEventSchema().getEventProperties();
+    } else {
+      return List.of();
+    }
+  }
 }
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpProperties.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpProperties.java
index ced0dd00e9..a17247a2f3 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpProperties.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpProperties.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.sdk.helpers;
 
-import org.apache.streampipes.commons.Utils;
 import org.apache.streampipes.model.schema.Enumeration;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.schema.EventPropertyList;
@@ -58,9 +57,9 @@ public class EpProperties {
   }
 
   public static EventPropertyList listNestedEp(Label label, String runtimeName, String
-      domainProperty, List<EventProperty> listItemProperties) {
+      semanticType, List<EventProperty> listItemProperties) {
     EventPropertyList list = listNestedEp(label, runtimeName, listItemProperties);
-    list.setDomainProperties(Arrays.asList(URI.create(domainProperty)));
+    list.setSemanticType(semanticType);
     return list;
   }
 
@@ -190,9 +189,8 @@ public class EpProperties {
    * @return {@link org.apache.streampipes.model.schema.EventPropertyList}
    */
   public static EventPropertyList listEp(Label label, String runtimeName, EventProperty eventProperty,
-                                         String domainProperty) {
-    return getPreparedProperty(label, new EventPropertyList(runtimeName, eventProperty, Utils.createURI
-        (domainProperty)));
+                                         String semanticType) {
+    return getPreparedProperty(label, new EventPropertyList(runtimeName, eventProperty, semanticType));
   }
 
   /**
@@ -287,25 +285,26 @@ public class EpProperties {
    * Creates a new primitive property of type integer and the provided domain property.
    *
    * @param runtimeName    The field identifier of the event property at runtime.
-   * @param domainProperty The semantics of the list property as a String. The string should correspond to a URI
-   *                       provided by a vocabulary. Use one of the vocabularies provided in
+   * @param semanticType The semantics of the list property as a String. Use one of the vocabularies provided in
    *                       {@link org.apache.streampipes.vocabulary} or create your own domain-specific vocabulary.
    * @return {@link org.apache.streampipes.model.schema.EventPropertyPrimitive}
    */
-  public static EventPropertyPrimitive integerEp(Label label, String runtimeName, String domainProperty) {
-    return ep(label, XSD.INTEGER.toString(), runtimeName, domainProperty);
+  public static EventPropertyPrimitive integerEp(Label label, String runtimeName, String semanticType) {
+    return ep(label, XSD.INTEGER.toString(), runtimeName, semanticType);
   }
 
   /**
    * Creates a new primitive property of type integer and the provided domain properties. In addition, the value range
    * of the property is restricted to the defined {@link org.apache.streampipes.model.schema.Enumeration}
    *
+   * @deprecated provide the semantic type as string
    * @param runtimeName      The field identifier of the event property at runtime.
    * @param domainProperties The semantics of the list property as a list of URIs. Use one of the vocabularies
    *                         provided in
    *                         {@link org.apache.streampipes.vocabulary} or create your own domain-specific vocabulary.
    * @return {@link org.apache.streampipes.model.schema.EventPropertyPrimitive}
    */
+  @Deprecated(forRemoval = true, since = "0.97.0")
   public static EventPropertyPrimitive integerEp(Label label, String runtimeName, List<URI> domainProperties) {
     return ep(label, XSD.INTEGER.toString(), runtimeName, domainProperties);
   }
@@ -317,15 +316,15 @@ public class EpProperties {
    *                       If you do not want to have a label besides the runtime name, use
    *                       {@link org.apache.streampipes.sdk.helpers.Labels}
    * @param runtimeName    The field identifier of the event property at runtime.
-   * @param domainProperty The semantics of the list property as a String. The string should correspond to a URI
-   *                       provided by a vocabulary. Use one of the vocabularies provided in
+   * @param semanticType The semantics of the list property as a String. Use one of the vocabularies provided in
    *                       {@link org.apache.streampipes.vocabulary} or create your own domain-specific vocabulary.
    * @return {@link org.apache.streampipes.model.schema.EventPropertyPrimitive}
    */
-  public static EventPropertyPrimitive longEp(Label label, String runtimeName, String domainProperty) {
-    return ep(label, XSD.LONG.toString(), runtimeName, domainProperty);
+  public static EventPropertyPrimitive longEp(Label label, String runtimeName, String semanticType) {
+    return ep(label, XSD.LONG.toString(), runtimeName, semanticType);
   }
 
+  @Deprecated(forRemoval = true, since = "0.97.0")
   public static EventPropertyPrimitive longEp(Label label, String runtimeName, List<URI> domainProperties) {
     return ep(label, XSD.LONG.toString(), runtimeName, domainProperties);
   }
@@ -353,14 +352,18 @@ public class EpProperties {
     return ep;
   }
 
-  public static EventPropertyPrimitive ep(Label label, String runtimeType, String runtimeName, String domainProperty) {
-    return getPreparedProperty(label, new EventPropertyPrimitive(runtimeType, runtimeName, "", Utils.createURI
-        (domainProperty)));
+  public static EventPropertyPrimitive ep(Label label,
+                                          String runtimeType,
+                                          String runtimeName,
+                                          String semanticType) {
+    return getPreparedProperty(label, new EventPropertyPrimitive(runtimeType, runtimeName, "", semanticType));
   }
 
+  @Deprecated(forRemoval = true, since = "0.97.0")
   private static EventPropertyPrimitive ep(Label label, String runtimeType, String runtimeName, List<URI>
       domainProperties) {
-    return getPreparedProperty(label, new EventPropertyPrimitive(runtimeType, runtimeName, "", domainProperties));
+    String semanticType = domainProperties.isEmpty() ? null : domainProperties.get(0).toString();
+    return getPreparedProperty(label, new EventPropertyPrimitive(runtimeType, runtimeName, "", semanticType));
   }
 
   private static <T extends EventProperty> T getPreparedProperty(Label label, T eventProperty) {
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpRequirements.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpRequirements.java
index 1d310fcb8e..77afed7fe7 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpRequirements.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/EpRequirements.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.sdk.helpers;
 
-import org.apache.streampipes.commons.Utils;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.schema.EventPropertyList;
 import org.apache.streampipes.model.schema.EventPropertyNested;
@@ -124,28 +123,48 @@ public class EpRequirements {
     return appendDomainProperty(datatypeReq(SO.NUMBER), domainProperty);
   }
 
-  private static <T extends EventProperty> EventProperty domainPropertyReq(String domainProperty,
-                                                                           Class<T> eventProperty) {
+  private static <T extends EventProperty> EventProperty semanticTypeReq(String semanticType,
+                                                                         Class<T> eventProperty) {
     EventProperty ep = null;
     try {
       ep = eventProperty.newInstance();
+      ep.setSemanticType(semanticType);
     } catch (InstantiationException | IllegalAccessException e) {
       e.printStackTrace();
     }
-    ep.setDomainProperties(Utils.createURI(domainProperty));
     return ep;
   }
 
+  public static EventPropertyPrimitive semanticTypeReq(String semanticType) {
+    return (EventPropertyPrimitive) semanticTypeReq(semanticType, EventPropertyPrimitive.class);
+  }
+
+  public static EventPropertyList semanticTypeReqList(String semanticType) {
+    return (EventPropertyList) semanticTypeReq(semanticType, EventPropertyList.class);
+  }
+
+  /**
+   * @param domainProperty the semantic type
+   * @return EventPropertyPrimitive
+   * @deprecated Use {@link EpRequirements#semanticTypeReq(String)} instead
+   */
+  @Deprecated(forRemoval = true, since = "0.97.0")
   public static EventPropertyPrimitive domainPropertyReq(String domainProperty) {
-    return (EventPropertyPrimitive) domainPropertyReq(domainProperty, EventPropertyPrimitive.class);
+    return (EventPropertyPrimitive) semanticTypeReq(domainProperty, EventPropertyPrimitive.class);
   }
 
+  /**
+   * @param domainProperty the semantic type
+   * @return EventPropertyList
+   * @deprecated Use {@link EpRequirements#semanticTypeReqList(String)} instead
+   */
+  @Deprecated(forRemoval = true, since = "0.97.0")
   public static EventPropertyList domainPropertyReqList(String domainProperty) {
-    return (EventPropertyList) domainPropertyReq(domainProperty, EventPropertyList.class);
+    return (EventPropertyList) semanticTypeReq(domainProperty, EventPropertyList.class);
   }
 
-  private static EventPropertyPrimitive appendDomainProperty(EventPropertyPrimitive property, String domainProperty) {
-    property.setDomainProperties(Utils.createURI(domainProperty));
+  private static EventPropertyPrimitive appendDomainProperty(EventPropertyPrimitive property, String semanticType) {
+    property.setSemanticType(semanticType);
     return property;
   }
 
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
index 681b180983..b8895a9b1f 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/Filetypes.java
@@ -29,6 +29,7 @@ public enum Filetypes {
   XLS("xls"),
   XLSX("xlsx"),
   XML("xml"),
+  YAML("yaml", "yml"),
   ZIP("zip");
 
   private final List<String> fileExtensions;
diff --git a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/FunctionRegistrationHandler.java b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/FunctionRegistrationHandler.java
index 04f1f370c4..8e17da40dd 100644
--- a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/FunctionRegistrationHandler.java
+++ b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/FunctionRegistrationHandler.java
@@ -26,6 +26,16 @@ import org.slf4j.LoggerFactory;
 
 import java.util.List;
 
+/**
+ * The {@code FunctionRegistrationHandler} class is responsible for registering
+ * a list of functions with the StreamPipes backend system.
+ *
+ * <p>Note: This class only handles the registration of the functions in the backend.
+ * The actual execution of the registered functions occurs in the extension service.
+ *
+ * <p>Once the registration is successful, a log entry is created to indicate
+ * the completion of the process.
+ */
 public class FunctionRegistrationHandler extends RegistrationHandler {
 
   private static final Logger LOG = LoggerFactory.getLogger(FunctionRegistrationHandler.class);
@@ -36,7 +46,8 @@ public class FunctionRegistrationHandler extends RegistrationHandler {
 
   @Override
   protected void performRequest(StreamPipesClient client) {
-    client.adminApi().registerFunctions(functions);
+    client.adminApi()
+          .registerFunctions(functions);
   }
 
   @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/EventPropertySerializer.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/EventPropertySerializer.java
new file mode 100644
index 0000000000..30e04cd69c
--- /dev/null
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/EventPropertySerializer.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.storage.couchdb.serializer;
+
+import org.apache.streampipes.model.schema.EventProperty;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+
+import java.lang.reflect.Type;
+
+public class EventPropertySerializer extends CouchDbJsonSerializer<EventProperty> {
+
+  private static final String DomainProperties = "domainProperties";
+
+  @Override
+  public EventProperty deserialize(JsonElement json,
+                                   Type typeOfT,
+                                   JsonDeserializationContext context) throws JsonParseException {
+
+    JsonObject jsonObject = json.getAsJsonObject();
+    String type = jsonObject.get("type").getAsString();
+    JsonElement element = jsonObject.get("properties");
+    if (element.getAsJsonObject().has(DomainProperties)) {
+      var domainProperties = element.getAsJsonObject().get(DomainProperties).getAsJsonArray();
+      if (!domainProperties.isEmpty()) {
+        element.getAsJsonObject().add("semanticType", new JsonPrimitive(domainProperties.get(0).getAsString()));
+      }
+      element.getAsJsonObject().remove(DomainProperties);
+
+    }
+
+    try {
+      return context.deserialize(element, Class.forName(type));
+    } catch (ClassNotFoundException cnfe) {
+      throw new JsonParseException("Unknown element type: " + type, cnfe);
+    }
+  }
+}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
index 37a2293ff4..685db7ee03 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
@@ -75,7 +75,7 @@ public class GsonSerializer {
 
   public static GsonBuilder getGsonBuilder() {
     GsonBuilder builder = new GsonBuilder();
-    builder.registerTypeAdapter(EventProperty.class, new CouchDbJsonSerializer<EventProperty>());
+    builder.registerTypeAdapter(EventProperty.class, new EventPropertySerializer());
     builder.registerTypeAdapter(StaticProperty.class, new CouchDbJsonSerializer<StaticProperty>());
     builder.registerTypeAdapter(OutputStrategy.class, new CouchDbJsonSerializer<OutputStrategy>());
     builder.registerTypeAdapter(TransportProtocol.class, new CouchDbJsonSerializer<TransportProtocol>());
diff --git a/ui/package-lock.json b/ui/package-lock.json
index faee36b4ce..054742cf18 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -7461,9 +7461,9 @@
       "dev": true
     },
     "node_modules/body-parser": {
-      "version": "1.20.2",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
-      "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+      "version": "1.20.3",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+      "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
       "dev": true,
       "dependencies": {
         "bytes": "3.1.2",
@@ -7474,7 +7474,7 @@
         "http-errors": "2.0.0",
         "iconv-lite": "0.4.24",
         "on-finished": "2.4.1",
-        "qs": "6.11.0",
+        "qs": "6.13.0",
         "raw-body": "2.5.2",
         "type-is": "~1.6.18",
         "unpipe": "1.0.0"
@@ -7512,12 +7512,12 @@
       }
     },
     "node_modules/body-parser/node_modules/qs": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+      "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
       "dev": true,
       "dependencies": {
-        "side-channel": "^1.0.4"
+        "side-channel": "^1.0.6"
       },
       "engines": {
         "node": ">=0.6"
@@ -10951,37 +10951,37 @@
       "dev": true
     },
     "node_modules/express": {
-      "version": "4.19.2",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
-      "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+      "version": "4.21.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
+      "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
       "dev": true,
       "dependencies": {
         "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
-        "body-parser": "1.20.2",
+        "body-parser": "1.20.3",
         "content-disposition": "0.5.4",
         "content-type": "~1.0.4",
         "cookie": "0.6.0",
         "cookie-signature": "1.0.6",
         "debug": "2.6.9",
         "depd": "2.0.0",
-        "encodeurl": "~1.0.2",
+        "encodeurl": "~2.0.0",
         "escape-html": "~1.0.3",
         "etag": "~1.8.1",
-        "finalhandler": "1.2.0",
+        "finalhandler": "1.3.1",
         "fresh": "0.5.2",
         "http-errors": "2.0.0",
-        "merge-descriptors": "1.0.1",
+        "merge-descriptors": "1.0.3",
         "methods": "~1.1.2",
         "on-finished": "2.4.1",
         "parseurl": "~1.3.3",
-        "path-to-regexp": "0.1.7",
+        "path-to-regexp": "0.1.10",
         "proxy-addr": "~2.0.7",
-        "qs": "6.11.0",
+        "qs": "6.13.0",
         "range-parser": "~1.2.1",
         "safe-buffer": "5.2.1",
-        "send": "0.18.0",
-        "serve-static": "1.15.0",
+        "send": "0.19.0",
+        "serve-static": "1.16.2",
         "setprototypeof": "1.2.0",
         "statuses": "2.0.1",
         "type-is": "~1.6.18",
@@ -11010,14 +11010,23 @@
         "ms": "2.0.0"
       }
     },
+    "node_modules/express/node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/express/node_modules/finalhandler": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
-      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+      "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
       "dev": true,
       "dependencies": {
         "debug": "2.6.9",
-        "encodeurl": "~1.0.2",
+        "encodeurl": "~2.0.0",
         "escape-html": "~1.0.3",
         "on-finished": "2.4.1",
         "parseurl": "~1.3.3",
@@ -11059,12 +11068,12 @@
       }
     },
     "node_modules/express/node_modules/qs": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+      "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
       "dev": true,
       "dependencies": {
-        "side-channel": "^1.0.4"
+        "side-channel": "^1.0.6"
       },
       "engines": {
         "node": ">=0.6"
@@ -11074,9 +11083,9 @@
       }
     },
     "node_modules/express/node_modules/send": {
-      "version": "0.18.0",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
-      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+      "version": "0.19.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+      "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
       "dev": true,
       "dependencies": {
         "debug": "2.6.9",
@@ -11097,6 +11106,15 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/express/node_modules/send/node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/express/node_modules/send/node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -11104,15 +11122,15 @@
       "dev": true
     },
     "node_modules/express/node_modules/serve-static": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
-      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+      "version": "1.16.2",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+      "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
       "dev": true,
       "dependencies": {
-        "encodeurl": "~1.0.2",
+        "encodeurl": "~2.0.0",
         "escape-html": "~1.0.3",
         "parseurl": "~1.3.3",
-        "send": "0.18.0"
+        "send": "0.19.0"
       },
       "engines": {
         "node": ">= 0.8.0"
@@ -14962,10 +14980,13 @@
       }
     },
     "node_modules/merge-descriptors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
-      "dev": true
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+      "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
     },
     "node_modules/merge-stream": {
       "version": "2.0.0",
@@ -17639,9 +17660,9 @@
       }
     },
     "node_modules/path-to-regexp": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
+      "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
       "dev": true
     },
     "node_modules/path-type": {
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 398a67c5f7..1ae8e4e32d 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -20,7 +20,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2024-09-18 15:50:05.
+// Generated using typescript-generator version 3.2.1263 on 2024-09-30 14:11:40.
 
 export class NamedStreamPipesEntity implements Storable {
     '@class':
@@ -1484,12 +1484,12 @@ export class EventProperty {
         | 'org.apache.streampipes.model.schema.EventPropertyPrimitive';
     'additionalMetadata': { [index: string]: any };
     'description': string;
-    'domainProperties': string[];
     'elementId': string;
     'label': string;
     'propertyScope': string;
     'runtimeId': string;
     'runtimeName': string;
+    'semanticType': string;
 
     static 'fromData'(
         data: EventProperty,
@@ -1504,14 +1504,12 @@ export class EventProperty {
             data.additionalMetadata,
         );
         instance.description = data.description;
-        instance.domainProperties = __getCopyArrayFn(__identity<string>())(
-            data.domainProperties,
-        );
         instance.elementId = data.elementId;
         instance.label = data.label;
         instance.propertyScope = data.propertyScope;
         instance.runtimeId = data.runtimeId;
         instance.runtimeName = data.runtimeName;
+        instance.semanticType = data.semanticType;
         return instance;
     }
 
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/types/semantic-type.ts b/ui/projects/streampipes/platform-services/src/lib/model/types/semantic-type.ts
index e0aff4fb37..e4869422e2 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/types/semantic-type.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/types/semantic-type.ts
@@ -42,14 +42,24 @@ export class SemanticType {
     }
 
     public static isTimestamp(property: EventProperty): boolean {
-        return property.domainProperties.includes(SemanticType.TIMESTAMP);
+        return this.equalsIgnoreCase(
+            SemanticType.TIMESTAMP,
+            property.semanticType,
+        );
     }
 
     public static isImage(property: EventProperty): boolean {
-        return property.domainProperties.includes(SemanticType.IMAGE);
+        return this.equalsIgnoreCase(SemanticType.IMAGE, property.semanticType);
     }
 
     public static isNumber(property: EventProperty): boolean {
-        return property.domainProperties.includes(SemanticType.SO_NUMBER);
+        return this.equalsIgnoreCase(
+            SemanticType.SO_NUMBER,
+            property.semanticType,
+        );
+    }
+
+    public static equalsIgnoreCase(str1: string, str2: string): boolean {
+        return str1?.toLowerCase() === str2?.toLowerCase();
     }
 }
diff --git a/ui/src/app/configuration/configuration.module.ts b/ui/src/app/configuration/configuration.module.ts
index f24da2f959..ff860383f5 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -96,6 +96,7 @@ import { FileOverviewComponent } from './files/file-overview/file-overview.compo
 import { FileUploadDialogComponent } from './dialog/file-upload/file-upload-dialog.component';
 import { FileRenameDialogComponent } from './dialog/file-rename/file-rename-dialog.component';
 import { MatDialogModule } from '@angular/material/dialog';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
 
 @NgModule({
     imports: [
@@ -120,6 +121,7 @@ import { MatDialogModule } from '@angular/material/dialog';
         CoreUiModule,
         ReactiveFormsModule,
         PlatformServicesModule,
+        MatProgressBarModule,
         RouterModule.forChild([
             {
                 path: '',
diff --git a/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.html b/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.html
index 6d83e5a5c6..ecec2cccdd 100644
--- a/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.html
+++ b/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.html
@@ -17,7 +17,10 @@
 -->
 
 <div class="sp-dialog-container">
-    <div class="sp-dialog-content p-15">
+    <div class="sp-dialog-content p-15" fxLayout="column">
+        <sp-warning-box *ngIf="uploadError" style="font-size: smaller">
+            {{ uploadErrorMessage }}
+        </sp-warning-box>
         <div fxFlex="100" *ngIf="this.duplicateFileNames.length === 0">
             <div fxFlex="100" style="margin: 5px; width: 100%">
                 <mat-form-field
@@ -57,7 +60,7 @@
                         color="accent"
                         matSuffix
                         mat-button
-                        style="min-width: 0px"
+                        style="min-width: 0"
                     >
                         <mat-icon *ngIf="uploadStatus < 99"
                             >insert_drive_file</mat-icon
diff --git a/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.ts b/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.ts
index 328cfe8494..beee8317b9 100644
--- a/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.ts
+++ b/ui/src/app/configuration/dialog/file-upload/file-upload-dialog.component.ts
@@ -39,6 +39,9 @@ export class FileUploadDialogComponent {
 
     uploadStatus = 0;
 
+    uploadError = false;
+    uploadErrorMessage = '';
+
     constructor(
         private dialogRef: DialogRef<FileUploadDialogComponent>,
         private filesService: FilesService,
@@ -73,6 +76,7 @@ export class FileUploadDialogComponent {
     }
 
     uploadFile(index: number): void {
+        this.uploadError = false;
         this.filesService
             .uploadFile(this.selectedUploadFiles.item(index))
             .subscribe(
@@ -90,7 +94,15 @@ export class FileUploadDialogComponent {
                         }
                     }
                 },
-                error => {},
+                error => {
+                    this.uploadError = true;
+                    if (error.error?.notifications?.length > 0) {
+                        this.uploadErrorMessage =
+                            error.error.notifications[0].title;
+                    } else {
+                        this.uploadErrorMessage = error.error;
+                    }
+                },
             );
     }
 
diff --git a/ui/src/app/connect/components/adapter-configuration/schema-editor/event-property-row/event-property-row.component.ts b/ui/src/app/connect/components/adapter-configuration/schema-editor/event-property-row/event-property-row.component.ts
index 93e776b6ec..59c01ae599 100644
--- a/ui/src/app/connect/components/adapter-configuration/schema-editor/event-property-row/event-property-row.component.ts
+++ b/ui/src/app/connect/components/adapter-configuration/schema-editor/event-property-row/event-property-row.component.ts
@@ -159,10 +159,7 @@ export class EventPropertyRowComponent implements OnInit {
     }
 
     isTimestampProperty(node) {
-        if (
-            node.domainProperties &&
-            node.domainProperties.some(dp => dp === SemanticType.TIMESTAMP)
-        ) {
+        if (node.semanticType !== undefined && SemanticType.isTimestamp(node)) {
             node.runtimeType = DataType.LONG;
             return true;
         } else {
diff --git a/ui/src/app/connect/components/adapter-configuration/schema-editor/event-schema/event-schema.component.ts b/ui/src/app/connect/components/adapter-configuration/schema-editor/event-schema/event-schema.component.ts
index 09423c2d32..da1b6c5a54 100644
--- a/ui/src/app/connect/components/adapter-configuration/schema-editor/event-schema/event-schema.component.ts
+++ b/ui/src/app/connect/components/adapter-configuration/schema-editor/event-schema/event-schema.component.ts
@@ -211,7 +211,7 @@ export class EventSchemaComponent implements OnChanges {
 
         eventProperty.runtimeName = runtimeName;
         eventProperty.runtimeType = DataType.STRING;
-        eventProperty.domainProperties = [];
+        eventProperty.semanticType = undefined;
         eventProperty.propertyScope = 'DIMENSION_PROPERTY';
         eventProperty.additionalMetadata = {};
 
@@ -230,7 +230,7 @@ export class EventSchemaComponent implements OnChanges {
         eventProperty.runtimeName = 'timestamp';
         eventProperty.label = 'Timestamp';
         eventProperty.description = 'The current timestamp value';
-        eventProperty.domainProperties = [SemanticType.TIMESTAMP];
+        eventProperty.semanticType = SemanticType.TIMESTAMP;
         eventProperty.propertyScope = 'HEADER_PROPERTY';
         eventProperty.runtimeType = DataType.LONG;
         eventProperty.additionalMetadata = {};
@@ -280,7 +280,7 @@ export class EventSchemaComponent implements OnChanges {
     private checkIfValid(eventSchema: EventSchema): boolean {
         this.timestampPresent = false;
         eventSchema.eventProperties.forEach(p => {
-            if (p.domainProperties.indexOf('http://schema.org/DateTime') > -1) {
+            if (SemanticType.isTimestamp(p)) {
                 this.timestampPresent = true;
             }
         });
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html
index 84732adcc3..4b6801488b 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.html
@@ -67,7 +67,7 @@
                     class="dmainProperty"
                     name="domainproperty"
                     id="domainproperty"
-                    [(ngModel)]="cachedProperty.domainProperties[0]"
+                    [(ngModel)]="cachedProperty.semanticType"
                     [matAutocomplete]="st"
                     [disabled]="isTimestampProperty"
                     [matAutocompleteDisabled]="isTimestampProperty"
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts
index 7c262a8e2f..4644e33e10 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-schema-transformation/edit-schema-transformation.component.ts
@@ -28,6 +28,8 @@ import { Observable } from 'rxjs';
 import { ShepherdService } from '../../../../../services/tour/shepherd.service';
 import {
     DataType,
+    EventPropertyPrimitive,
+    EventPropertyUnion,
     SemanticType,
     SemanticTypesRestService,
 } from '@streampipes/platform-services';
@@ -40,7 +42,7 @@ import { Router } from '@angular/router';
 })
 export class EditSchemaTransformationComponent implements OnInit {
     @Input()
-    cachedProperty: any;
+    cachedProperty: EventPropertyUnion;
 
     @Input() isTimestampProperty: boolean;
     @Input() isNestedProperty: boolean;
@@ -79,11 +81,12 @@ export class EditSchemaTransformationComponent implements OnInit {
     editTimestampDomainProperty(checked: boolean) {
         if (checked) {
             this.isTimestampProperty = true;
-            this.cachedProperty.domainProperties = [SemanticType.TIMESTAMP];
+            this.cachedProperty.semanticType = SemanticType.TIMESTAMP;
             this.cachedProperty.propertyScope = 'HEADER_PROPERTY';
-            this.cachedProperty.runtimeType = DataType.LONG;
+            (this.cachedProperty as EventPropertyPrimitive).runtimeType =
+                DataType.LONG;
         } else {
-            this.cachedProperty.domainProperties = [];
+            this.cachedProperty.semanticType = undefined;
             this.cachedProperty.propertyScope = 'MEASUREMENT_PROPERTY';
             this.isTimestampProperty = false;
         }
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
index f5b527b7e1..0cff8aefd4 100644
--- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
+++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
@@ -149,9 +149,7 @@ export class EditEventPropertyComponent implements OnInit {
         this.property.description = this.cachedProperty.description;
         this.property.elementId = this.cachedProperty.elementId;
 
-        // remove undefined from domain properties array
-        this.property.domainProperties =
-            this.cachedProperty.domainProperties.filter(n => n);
+        this.property.semanticType = this.cachedProperty.semanticType;
         this.property.runtimeName = this.cachedProperty.runtimeName;
         this.property.propertyScope = this.cachedProperty.propertyScope;
 
diff --git a/ui/src/app/connect/filter/timestamp.pipe.ts b/ui/src/app/connect/filter/timestamp.pipe.ts
index d3bd4b5c43..e863268f70 100644
--- a/ui/src/app/connect/filter/timestamp.pipe.ts
+++ b/ui/src/app/connect/filter/timestamp.pipe.ts
@@ -30,8 +30,6 @@ export class TimestampPipe implements PipeTransform {
     constructor() {}
 
     transform(items: EventPropertyUnion[]): EventPropertyUnion[] {
-        return items.filter(item =>
-            item.domainProperties.some(dp => dp === SemanticType.TIMESTAMP),
-        );
+        return items.filter(item => SemanticType.isTimestamp(item));
     }
 }
diff --git a/ui/src/app/connect/services/transformation-rule.service.ts b/ui/src/app/connect/services/transformation-rule.service.ts
index 2d04eb8876..b79883961a 100644
--- a/ui/src/app/connect/services/transformation-rule.service.ts
+++ b/ui/src/app/connect/services/transformation-rule.service.ts
@@ -89,9 +89,7 @@ export class TransformationRuleService {
                 rule.label = ep.label;
                 rule.description = ep.description;
                 rule.propertyScope = ep.propertyScope as PropertyScope;
-                if (ep.domainProperties.length > 0) {
-                    rule.semanticType = ep.domainProperties[0];
-                }
+                rule.semanticType = ep.semanticType;
                 rule.measurementUnit = ep.measurementUnit;
                 rule.staticValue =
                     this.staticValueTransformService.getStaticValue(
@@ -569,9 +567,7 @@ export class TransformationRuleService {
     }
 
     isTimestampProperty(property: EventPropertyPrimitive) {
-        return property.domainProperties.some(
-            dp => dp === SemanticType.TIMESTAMP,
-        );
+        return SemanticType.isTimestamp(property);
     }
 
     private getDatatypeTransformRules(
diff --git a/ui/src/app/core-ui/static-properties/static-property.component.html b/ui/src/app/core-ui/static-properties/static-property.component.html
index e416735c84..3f43c9bd03 100644
--- a/ui/src/app/core-ui/static-properties/static-property.component.html
+++ b/ui/src/app/core-ui/static-properties/static-property.component.html
@@ -94,6 +94,7 @@
                 [parentForm]="parentForm"
                 [completedStaticProperty]="completedStaticProperty"
                 [adapterId]="adapterId"
+                (updateEmitter)="emitUpdate($event)"
             >
             </sp-app-static-runtime-resolvable-any-input>
 
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html
index 4690c0f00c..ac1c4f7e54 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.html
@@ -17,48 +17,65 @@
   -->
 
 <div id="formWrapper" fxFlex="100" fxLayout="column">
-    <div>
+    <div fxLayout="row" class="mb-10">
+        <button
+            mat-button
+            mat-raised-button
+            color="accent"
+            class="small-button"
+            (click)="selectAll(true)"
+            [disabled]="!showOptions"
+        >
+            <span>Select all</span>
+        </button>
+        <button
+            mat-button
+            mat-raised-button
+            class="mat-basic small-button"
+            (click)="selectAll(false)"
+            [disabled]="!showOptions"
+        >
+            <span>Select none</span>
+        </button>
         <button
             mat-button
             mat-raised-button
             color="accent"
             class="small-button"
             (click)="loadOptionsFromRestApi()"
-            style="margin-right: 10px; margin-left: 10px"
             [disabled]="!showOptions"
         >
             <span>Reload</span>
         </button>
+        <mat-spinner
+            *ngIf="loading"
+            color="accent"
+            [mode]="'indeterminate'"
+            [diameter]="15"
+        ></mat-spinner>
     </div>
-    <div
-        *ngIf="!staticProperty.horizontalRendering"
-        fxLayout="column"
-        style="margin-top: 10px"
-    >
+    <div *ngIf="!staticProperty.horizontalRendering" fxLayout="column">
         <mat-checkbox
             style="padding-left: 10px"
             color="accent"
             *ngFor="let option of staticProperty.options"
             [(ngModel)]="option.selected"
+            (ngModelChange)="checkEmitUpdate()"
         >
             {{ option.name }}
         </mat-checkbox>
     </div>
-    <div fxLayout="column" *ngIf="!showOptions && !loading" class="mt-10">
+    <div fxLayout="column" *ngIf="!showOptions && !loading" class="mb-10">
         <span>(waiting for input)</span>
     </div>
-    <div fxLayout="column" *ngIf="loading">
-        <mat-spinner
-            color="accent"
-            [mode]="'indeterminate'"
-            [diameter]="20"
-        ></mat-spinner>
-    </div>
 
-    <div *ngIf="staticProperty.horizontalRendering">
+    <div *ngIf="staticProperty.horizontalRendering && showOptions">
         <mat-form-field style="width: 100%" color="accent">
-            <mat-label>{{ staticProperty.label }}</mat-label>
-            <mat-select multiple [(ngModel)]="option.selected">
+            <mat-select
+                multiple
+                [(ngModel)]="selectedOptions"
+                (selectionChange)="onSelectionChange()"
+            >
                 <mat-option
                     *ngFor="let option of staticProperty.options"
                     [value]="option"
@@ -66,7 +83,6 @@
                     {{ option.name }}
                 </mat-option>
             </mat-select>
-            <mat-hint>{{ staticProperty.description }}</mat-hint>
         </mat-form-field>
     </div>
 </div>
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
index 2fb2ea4da5..6d84538535 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
@@ -18,11 +18,13 @@
 
 import { Component, OnInit } from '@angular/core';
 import {
+    Option,
     RuntimeResolvableAnyStaticProperty,
     StaticPropertyUnion,
 } from '@streampipes/platform-services';
 import { RuntimeResolvableService } from '../static-runtime-resolvable-input/runtime-resolvable.service';
 import { BaseRuntimeResolvableSelectionInput } from '../static-runtime-resolvable-input/base-runtime-resolvable-selection-input';
+import { MatSelectChange } from '@angular/material/select';
 
 @Component({
     selector: 'sp-app-static-runtime-resolvable-any-input',
@@ -33,25 +35,40 @@ export class StaticRuntimeResolvableAnyInputComponent
     extends BaseRuntimeResolvableSelectionInput<RuntimeResolvableAnyStaticProperty>
     implements OnInit
 {
+    selectedOptions: Option[] = [];
+
     constructor(runtimeResolvableService: RuntimeResolvableService) {
         super(runtimeResolvableService);
     }
 
     ngOnInit() {
         super.onInit();
+        this.selectedOptions = this.staticProperty.options.filter(
+            o => o.selected,
+        );
+    }
+
+    selectAll(select: boolean): void {
+        this.staticProperty.options.forEach(o => (o.selected = select));
+        this.selectedOptions = select ? this.staticProperty.options : [];
+        this.emitUpdate(true);
+    }
+
+    onSelectionChange(): void {
+        this.staticProperty.options.forEach(option => {
+            option.selected = this.selectedOptions.includes(option);
+        });
     }
 
-    select(id) {
-        for (const option of this.staticProperty.options) {
-            option.selected = false;
-        }
-        this.staticProperty.options.find(
-            option => option.elementId === id,
-        ).selected = true;
+    checkEmitUpdate(): void {
+        this.emitUpdate(true);
     }
 
     afterOptionsLoaded(staticProperty: RuntimeResolvableAnyStaticProperty) {
         this.staticProperty.options = staticProperty.options;
+        this.selectedOptions = this.staticProperty.options.filter(
+            o => o.selected,
+        );
     }
 
     parse(
diff --git a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.html b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.html
index 0863899fa6..e3a4e5c69c 100644
--- a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.html
+++ b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.html
@@ -22,7 +22,6 @@
             fxFlex
             formControlName="{{ fieldName }}"
             color="accent"
-            required
             [attr.data-cy]="fieldName"
         >
             {{ staticProperty.description }}
diff --git a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
index 64e17a6005..e74274ae7f 100644
--- a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
@@ -33,6 +33,7 @@ export class StaticSlideToggleComponent
     ngOnInit(): void {
         this.addValidator(this.staticProperty.selected, Validators.required);
         this.enableValidators();
+        this.emitUpdate();
     }
 
     emitUpdate() {
diff --git a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
index 54693b732e..768ee61ebb 100644
--- a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
@@ -57,7 +57,7 @@ export class TableWidgetComponent
 
         this.widgetDataConfig.eventSchema.eventProperties.forEach(
             (key, index) => {
-                this.semanticTypes[key.runtimeName] = key.domainProperties[0];
+                this.semanticTypes[key.runtimeName] = key.semanticType;
             },
         );
         this.semanticTypes[BaseStreamPipesWidget.TIMESTAMP_KEY] =
diff --git a/ui/src/app/dashboard/sdk/ep-requirements.ts b/ui/src/app/dashboard/sdk/ep-requirements.ts
index 3196a11ced..58b830c43f 100644
--- a/ui/src/app/dashboard/sdk/ep-requirements.ts
+++ b/ui/src/app/dashboard/sdk/ep-requirements.ts
@@ -104,9 +104,9 @@ export class EpRequirements {
         return listEp;
     }
 
-    static domainPropertyReq(domainProperty: string): EventPropertyPrimitive {
+    static domainPropertyReq(semanticType: string): EventPropertyPrimitive {
         const eventProperty = EpRequirements.ep();
-        eventProperty.domainProperties = [domainProperty];
+        eventProperty.semanticType = semanticType;
         return eventProperty;
     }
 
diff --git a/ui/src/app/dashboard/sdk/matching/domain-property-match.ts b/ui/src/app/dashboard/sdk/matching/domain-property-match.ts
index 3c319f5866..92c9c1f5e7 100644
--- a/ui/src/app/dashboard/sdk/matching/domain-property-match.ts
+++ b/ui/src/app/dashboard/sdk/matching/domain-property-match.ts
@@ -17,22 +17,17 @@
  */
 
 export class DomainPropertyMatch {
-    match(
-        domainPropertyRequirements: string[],
-        domainPropertyOffers: string[],
-    ) {
+    match(domainPropertyRequirement: string, domainPropertyOffer: string) {
         if (
-            domainPropertyRequirements === undefined ||
-            domainPropertyRequirements.length === 0
+            domainPropertyRequirement === undefined ||
+            domainPropertyRequirement === ''
         ) {
             return true;
         } else {
-            if (!domainPropertyOffers) {
+            if (!domainPropertyOffer) {
                 return false;
             } else {
-                return (
-                    domainPropertyRequirements[0] === domainPropertyOffers[0]
-                );
+                return domainPropertyRequirement === domainPropertyOffer;
             }
         }
     }
diff --git a/ui/src/app/dashboard/sdk/matching/primitive-property-match.ts b/ui/src/app/dashboard/sdk/matching/primitive-property-match.ts
index dea6f256a3..8ecb8ebe81 100644
--- a/ui/src/app/dashboard/sdk/matching/primitive-property-match.ts
+++ b/ui/src/app/dashboard/sdk/matching/primitive-property-match.ts
@@ -29,8 +29,8 @@ export class PrimitivePropertyMatch {
                     offer.runtimeType,
                 ) &&
                 new DomainPropertyMatch().match(
-                    requirement.domainProperties,
-                    offer.domainProperties,
+                    requirement.semanticType,
+                    offer.semanticType,
                 )
             );
         } else {
diff --git a/ui/src/app/data-explorer/services/data-explorer-field-provider-service.ts b/ui/src/app/data-explorer/services/data-explorer-field-provider-service.ts
index 40a9e91309..166ba89413 100644
--- a/ui/src/app/data-explorer/services/data-explorer-field-provider-service.ts
+++ b/ui/src/app/data-explorer/services/data-explorer-field-provider-service.ts
@@ -113,7 +113,7 @@ export class DataExplorerFieldProviderService {
                 dimension: this.isDimensionProperty(property),
                 numeric: this.isNumber(property) || aggregation === 'COUNT',
                 binary: this.isBoolean(property),
-                semanticTypes: property.domainProperties,
+                semanticTypes: [property.semanticType],
             },
         };
         provider.allFields.push(field);
@@ -156,7 +156,7 @@ export class DataExplorerFieldProviderService {
     }
 
     public isTimestamp(p: EventProperty) {
-        return p.domainProperties.some(dp => dp === SemanticType.TIMESTAMP);
+        return SemanticType.isTimestamp(p);
     }
 
     public getAddedFields(
diff --git a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
index 9c6d61eb2a..1ebc5d00e6 100644
--- a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
+++ b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.html
@@ -75,7 +75,7 @@
             <mat-form-field fxFlex color="accent">
                 <mat-label>Semantic type</mat-label>
                 <input
-                    [(ngModel)]="ep.domainProperties[0]"
+                    [(ngModel)]="ep.semanticType"
                     [disabled]="restrictedEditMode"
                     data-cy="semantic-type"
                     fxFlex
diff --git a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
index 94576ade12..97170d9547 100644
--- a/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
+++ b/ui/src/app/editor/components/output-strategy/user-defined-output/user-defined-output.component.ts
@@ -81,7 +81,7 @@ export class UserDefinedOutputStrategyComponent
         const ep = {} as EventPropertyPrimitive;
         ep['@class'] =
             'org.apache.streampipes.model.schema.EventPropertyPrimitive';
-        ep.domainProperties = [];
+        ep.semanticType = undefined;
         ep.elementId =
             'urn:streampipes.org:spi:eventpropertyprimitive:' +
             this.idGeneratorService.generatePrefixedId();
diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html
index 56c283b6c0..6ff8ea6a14 100644
--- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html
+++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.html
@@ -62,10 +62,18 @@
                     name="pipelineName"
                     (blur)="triggerTutorial()"
                 />
+                <mat-error
+                    >Pipeline name must have between 3 and 40
+                    characters.</mat-error
+                >
             </mat-form-field>
             <mat-form-field fxFlex color="accent">
                 <mat-label>Description</mat-label>
                 <input [formControlName]="'pipelineDescription'" matInput />
+                <mat-error
+                    >Pipeline description must not have more than 80
+                    characters.</mat-error
+                >
             </mat-form-field>
         </div>
     </form>
diff --git a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts
index 6f32859192..d75b2c1aed 100644
--- a/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts
+++ b/ui/src/app/editor/dialog/save-pipeline/save-pipeline-settings/save-pipeline-settings.component.ts
@@ -51,6 +51,7 @@ export class SavePipelineSettingsComponent implements OnInit {
             'pipelineName',
             new UntypedFormControl(this.pipeline.name, [
                 Validators.required,
+                Validators.minLength(3),
                 Validators.maxLength(40),
             ]),
         );
diff --git a/ui/src/app/files/files.module.ts b/ui/src/app/files/files.module.ts
deleted file mode 100644
index 991569618d..0000000000
--- a/ui/src/app/files/files.module.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { FlexLayoutModule } from '@ngbracket/ngx-layout';
-import { MatButtonModule } from '@angular/material/button';
-import { MatGridListModule } from '@angular/material/grid-list';
-import { MatIconModule } from '@angular/material/icon';
-import { MatDividerModule } from '@angular/material/divider';
-import { MatListModule } from '@angular/material/list';
-import { FilesComponent } from '../configuration/files/files.component';
-import { MatTabsModule } from '@angular/material/tabs';
-import { CoreUiModule } from '../core-ui/core-ui.module';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatProgressBarModule } from '@angular/material/progress-bar';
-import { MatInputModule } from '@angular/material/input';
-import { ServicesModule } from '../services/services.module';
-import { MatTableModule } from '@angular/material/table';
-import { MatPaginatorModule } from '@angular/material/paginator';
-import { MatChipsModule } from '@angular/material/chips';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { PlatformServicesModule } from '@streampipes/platform-services';
-import { RouterModule } from '@angular/router';
-import { SharedUiModule } from '@streampipes/shared-ui';
-import { MatDialogModule } from '@angular/material/dialog';
-
-@NgModule({
-    imports: [
-        CommonModule,
-        CoreUiModule,
-        FlexLayoutModule,
-        FormsModule,
-        ReactiveFormsModule,
-        MatButtonModule,
-        MatChipsModule,
-        MatFormFieldModule,
-        MatGridListModule,
-        MatIconModule,
-        MatInputModule,
-        MatDividerModule,
-        MatListModule,
-        MatPaginatorModule,
-        MatProgressBarModule,
-        MatTableModule,
-        MatTabsModule,
-        MatTooltipModule,
-        PlatformServicesModule,
-        ServicesModule,
-        SharedUiModule,
-        RouterModule.forChild([
-            {
-                path: '',
-                children: [
-                    {
-                        path: '',
-                        component: FilesComponent,
-                    },
-                ],
-            },
-        ]),
-        MatDialogModule,
-    ],
-    declarations: [],
-    providers: [],
-})
-export class FilesModule {}
diff --git a/ui/src/app/files/files.routes.ts b/ui/src/app/files/files.routes.ts
deleted file mode 100644
index be69607a13..0000000000
--- a/ui/src/app/files/files.routes.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import { SpBreadcrumbItem } from '@streampipes/shared-ui';
-
-export class SpFilesRoutes {
-    static FILES_BASE_LINK = 'files';
-    static BASE: SpBreadcrumbItem = {
-        label: 'File Management',
-        link: [SpFilesRoutes.FILES_BASE_LINK],
-    };
-}


Test patch:
diff --git a/streampipes-client-python/tests/client/test_endpoint.py b/streampipes-client-python/tests/client/test_endpoint.py
index ccf1a3bee3..5b71d83531 100644
--- a/streampipes-client-python/tests/client/test_endpoint.py
+++ b/streampipes-client-python/tests/client/test_endpoint.py
@@ -53,7 +53,7 @@ class TestStreamPipesEndpoints(TestCase):
                             "label": "Density",
                             "description": "Denotes the current density of the fluid",
                             "runtimeName": "density",
-                            "domainProperties": ["http://schema.org/Number"],
+                            "semanticType": "http://schema.org/Number",
                             "propertyScope": "MEASUREMENT_PROPERTY",
                             "runtimeId": None,
                             "runtimeType": "http://www.w3.org/2001/XMLSchema#float",
@@ -66,7 +66,7 @@ class TestStreamPipesEndpoints(TestCase):
                             "label": "Temperature",
                             "description": "Denotes the current temperature in degrees celsius",
                             "runtimeName": "temperature",
-                            "domainProperties": ["http://schema.org/Number"],
+                            "semanticType": "http://schema.org/Number",
                             "propertyScope": "MEASUREMENT_PROPERTY",
                             "runtimeId": None,
                             "runtimeType": "http://www.w3.org/2001/XMLSchema#float",
@@ -131,7 +131,7 @@ class TestStreamPipesEndpoints(TestCase):
                             "label": "Density",
                             "description": "Denotes the current density of the fluid",
                             "runtimeName": "density",
-                            "domainProperties": ["http://schema.org/Number"],
+                            "semanticType": "http://schema.org/Number",
                             "propertyScope": "MEASUREMENT_PROPERTY",
                             "runtimeId": None,
                             "runtimeType": "http://www.w3.org/2001/XMLSchema#float",
@@ -144,7 +144,7 @@ class TestStreamPipesEndpoints(TestCase):
                             "label": "Temperature",
                             "description": "Denotes the current temperature in degrees celsius",
                             "runtimeName": "temperature",
-                            "domainProperties": ["http://schema.org/Number"],
+                            "semanticType": "http://schema.org/Number",
                             "propertyScope": "MEASUREMENT_PROPERTY",
                             "runtimeId": None,
                             "runtimeType": "http://www.w3.org/2001/XMLSchema#float",
diff --git a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/compact/generator/AdapterSchemaGeneratorTest.java b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/compact/generator/AdapterSchemaGeneratorTest.java
index ef123ae80d..56d3203519 100644
--- a/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/compact/generator/AdapterSchemaGeneratorTest.java
+++ b/streampipes-connect-management/src/test/java/org/apache/streampipes/connect/management/management/compact/generator/AdapterSchemaGeneratorTest.java
@@ -72,6 +72,6 @@ public class AdapterSchemaGeneratorTest {
     );
     assertEquals("description", properties.get(0).getDescription());
     assertEquals(PropertyScope.DIMENSION_PROPERTY.name(), properties.get(0).getPropertyScope());
-    assertEquals("semanticType", properties.get(0).getDomainProperties().get(0).toString());
+    assertEquals("semanticType", properties.get(0).getSemanticType());
   }
 }
diff --git a/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilterTest.java b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilterTest.java
new file mode 100644
index 0000000000..0b9acb8a62
--- /dev/null
+++ b/streampipes-data-explorer-influx/src/test/java/org/apache/streampipes/dataexplorer/influx/PropertyDuplicateFilterTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.dataexplorer.influx;
+
+import org.apache.streampipes.model.runtime.field.PrimitiveField;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class PropertyDuplicateFilterTest {
+
+  @Test
+  public void testDuplicate() {
+    var filter = new PropertyDuplicateFilter(true);
+    var field = new PrimitiveField(null, null, 1);
+    var result = filter.shouldIgnoreField("test", field);
+
+    assertFalse(result);
+
+    field = new PrimitiveField(null, null, 2);
+    result = filter.shouldIgnoreField("test", field);
+    assertFalse(result);
+
+    field = new PrimitiveField(null, null, 2);
+    result = filter.shouldIgnoreField("test1", field);
+    assertFalse(result);
+
+    field = new PrimitiveField(null, null, 2);
+    result = filter.shouldIgnoreField("test", field);
+    assertTrue(result);
+  }
+
+  @Test
+  public void testDuplicateDeactivated() {
+    var filter = new PropertyDuplicateFilter(false);
+    var field = new PrimitiveField(null, null, 1);
+    var result = filter.shouldIgnoreField("test", field);
+
+    assertFalse(result);
+
+    field = new PrimitiveField(null, null, 1);
+    result = filter.shouldIgnoreField("test", field);
+    assertFalse(result);
+  }
+}
diff --git a/streampipes-data-explorer-iotdb/src/test/java/org/apache/streampipes/dataexplorer/iotdb/IotDbPropertyConverterTest.java b/streampipes-data-explorer-iotdb/src/test/java/org/apache/streampipes/dataexplorer/iotdb/IotDbPropertyConverterTest.java
index 5b7085784e..0c09c71977 100644
--- a/streampipes-data-explorer-iotdb/src/test/java/org/apache/streampipes/dataexplorer/iotdb/IotDbPropertyConverterTest.java
+++ b/streampipes-data-explorer-iotdb/src/test/java/org/apache/streampipes/dataexplorer/iotdb/IotDbPropertyConverterTest.java
@@ -18,12 +18,13 @@
 
 package org.apache.streampipes.dataexplorer.iotdb;
 
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.streampipes.commons.exceptions.SpRuntimeException;
 import org.apache.streampipes.model.runtime.field.PrimitiveField;
 import org.apache.streampipes.model.schema.EventPropertyPrimitive;
 import org.apache.streampipes.vocabulary.SO;
 import org.apache.streampipes.vocabulary.XSD;
+
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -42,7 +43,7 @@ public class IotDbPropertyConverterTest {
   @Test
   public void convertPrimitivePropertyInteger() {
 
-    var property = new EventPropertyPrimitive(XSD.INTEGER.toString(), "test", null, null);
+    var property = new EventPropertyPrimitive(XSD.INTEGER.toString(), "test", null, "");
     var field = new PrimitiveField("test", "test", 5);
 
     var result = new IotDbPropertyConverter().convertPrimitiveProperty(property, field, "sanitizedTest");
@@ -55,7 +56,7 @@ public class IotDbPropertyConverterTest {
   @Test
   public void convertPrimitivePropertyString() {
 
-    var property = new EventPropertyPrimitive(XSD.STRING.toString(), "test", null, null);
+    var property = new EventPropertyPrimitive(XSD.STRING.toString(), "test", null, "");
     var field = new PrimitiveField("test", "test", "value");
 
     var result = new IotDbPropertyConverter().convertPrimitiveProperty(property, field, "sanitizedTest");
@@ -68,7 +69,7 @@ public class IotDbPropertyConverterTest {
   @Test
   public void convertPrimitivePropertyFloat() {
 
-    var property = new EventPropertyPrimitive(XSD.FLOAT.toString(), "test", null, null);
+    var property = new EventPropertyPrimitive(XSD.FLOAT.toString(), "test", null, "");
     var field = new PrimitiveField("test", "test", 0.5f);
 
     var result = new IotDbPropertyConverter().convertPrimitiveProperty(property, field, "sanitizedTest");
@@ -81,7 +82,7 @@ public class IotDbPropertyConverterTest {
   @Test
   public void convertPrimitivePropertyNumber() {
 
-    var property = new EventPropertyPrimitive(SO.NUMBER, "test", null, null);
+    var property = new EventPropertyPrimitive(SO.NUMBER, "test", null, "");
     var field = new PrimitiveField("test", "test", 5.24);
 
     var result = new IotDbPropertyConverter().convertPrimitiveProperty(property, field, "sanitizedTest");
@@ -94,7 +95,7 @@ public class IotDbPropertyConverterTest {
   @Test
   public void convertPrimitivePropertyUnknown() {
 
-    var property = new EventPropertyPrimitive(XSD.ANY_TYPE.toString(), "test", null, null);
+    var property = new EventPropertyPrimitive(XSD.ANY_TYPE.toString(), "test", null, "");
     var field = new PrimitiveField("test", "test", 5);
 
     assertThrows(SpRuntimeException.class, () -> new IotDbPropertyConverter().convertPrimitiveProperty(property, field, "sanitizedTest"));
diff --git a/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessorTest.java b/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessorTest.java
new file mode 100644
index 0000000000..b93127a352
--- /dev/null
+++ b/streampipes-extensions/streampipes-processors-transformation-jvm/src/test/java/org/apache/streampipes/processors/transformation/jvm/processor/transformtoboolean/TransformToBooleanProcessorTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.processors.transformation.jvm.processor.transformtoboolean;
+
+import org.apache.streampipes.test.executors.PrefixStrategy;
+import org.apache.streampipes.test.executors.ProcessingElementTestExecutor;
+import org.apache.streampipes.test.executors.TestConfiguration;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+public class TransformToBooleanProcessorTest {
+
+  @Test
+  void onEvent() {
+
+    var processor = new TransformToBooleanProcessor();
+
+    List<Map<String, Object>> inputEvents = List.of(Map.of(
+        "numberBoolean", 0,
+        "stringBoolean", "true",
+        "stringBooleanFalse", "false",
+        "floatBoolean", 1.0
+    ));
+
+    List<Map<String, Object>> outputEvents = List.of(Map.of(
+        "numberBoolean", false,
+        "stringBoolean", true,
+        "stringBooleanFalse", false,
+        "floatBoolean", true
+    ));
+
+    var configuration = TestConfiguration
+        .builder()
+        .config(TransformToBooleanProcessor.TRANSFORM_FIELDS_ID, List.of(
+            "s0::numberBoolean", "s0::stringBoolean", "s0::stringBooleanFalse", "s0::floatBoolean"))
+        .prefixStrategy(PrefixStrategy.SAME_PREFIX)
+        .build();
+
+    var testExecutor = new ProcessingElementTestExecutor(processor, configuration);
+
+    testExecutor.run(inputEvents, outputEvents);
+  }
+}
diff --git a/streampipes-extensions/streampipes-sinks-internal-jvm/src/test/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2Test.java b/streampipes-extensions/streampipes-sinks-internal-jvm/src/test/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2Test.java
new file mode 100644
index 0000000000..3a3e2e272f
--- /dev/null
+++ b/streampipes-extensions/streampipes-sinks-internal-jvm/src/test/java/org/apache/streampipes/sinks/internal/jvm/datalake/migrations/DataLakeSinkMigrationV2Test.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.sinks.internal.jvm.datalake.migrations;
+
+import org.apache.streampipes.model.SpDataStream;
+import org.apache.streampipes.model.graph.DataSinkInvocation;
+import org.apache.streampipes.model.migration.MigrationResult;
+import org.apache.streampipes.model.schema.EventSchema;
+import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.model.staticproperty.RuntimeResolvableAnyStaticProperty;
+import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
+import org.apache.streampipes.sdk.extractor.DataSinkParameterExtractor;
+import org.apache.streampipes.sdk.utils.Datatypes;
+import org.apache.streampipes.sinks.internal.jvm.datalake.DataLakeSink;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+public class DataLakeSinkMigrationV2Test {
+
+  @Test
+  public void migrate() {
+    var dataLakeSinkMigrationV2 = new DataLakeSinkMigrationV2();
+
+    var stream = new SpDataStream();
+    stream.setEventSchema(makeSchema());
+    var extractor = mock(DataSinkParameterExtractor.class);
+    var invocation = new DataSinkInvocation();
+    invocation.setStaticProperties(new ArrayList<>());
+    invocation.setInputStreams(List.of(stream));
+
+    var actual = dataLakeSinkMigrationV2.migrate(invocation, extractor);
+
+    Assertions.assertTrue(actual.success());
+    Assertions.assertEquals(actual.element()
+        .getStaticProperties()
+        .size(), 2);
+    var dimensionConfig = getAnyStaticProperty(actual);
+    Assertions.assertEquals(dimensionConfig.getInternalName(), DataLakeSink.DIMENSIONS_KEY);
+    Assertions.assertEquals(dimensionConfig.getOptions().size(), 3);
+    Assertions.assertTrue(dimensionConfig.getOptions().get(0).isSelected());
+    Assertions.assertFalse(dimensionConfig.getOptions().get(1).isSelected());
+    Assertions.assertFalse(dimensionConfig.getOptions().get(2).isSelected());
+  }
+
+  private static RuntimeResolvableAnyStaticProperty getAnyStaticProperty(MigrationResult<DataSinkInvocation> actual) {
+    return (RuntimeResolvableAnyStaticProperty) actual.element()
+        .getStaticProperties()
+        .get(0);
+  }
+
+  private static EventSchema makeSchema() {
+    return new EventSchema(
+        List.of(
+            PrimitivePropertyBuilder
+                .create(Datatypes.String, "a")
+                .scope(PropertyScope.DIMENSION_PROPERTY)
+                .build(),
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, "b")
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .build(),
+            PrimitivePropertyBuilder
+                .create(Datatypes.Integer, "c")
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .build(),
+            PrimitivePropertyBuilder
+                .create(Datatypes.Boolean, "d")
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .build()
+        )
+    );
+  }
+}
diff --git a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatchTest.java b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatchTest.java
index 50026e5757..e84ba4c087 100644
--- a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatchTest.java
+++ b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/ListPropertyMatchTest.java
@@ -24,7 +24,6 @@ import org.apache.streampipes.model.schema.EventPropertyList;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -33,13 +32,12 @@ public class ListPropertyMatchTest {
 
   @Test
   public void matchSameDomainProperty() {
-    List<URI> domainProperties = new ArrayList<>();
-    domainProperties.add(URI.create("http://test.org/property"));
+    var semanticType = "http://test.org/property";
 
     EventPropertyList offer = new EventPropertyList();
-    offer.setDomainProperties(domainProperties);
+    offer.setSemanticType(semanticType);
     EventPropertyList requirement = new EventPropertyList();
-    requirement.setDomainProperties(domainProperties);
+    requirement.setSemanticType(semanticType);
 
     List<MatchingResultMessage> errorLog = new ArrayList<>();
 
@@ -61,4 +59,4 @@ public class ListPropertyMatchTest {
     Assertions.assertTrue(result);
   }
 
-}
\ No newline at end of file
+}
diff --git a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestDomainPropertyMatch.java b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestSemanticTypeMatch.java
similarity index 63%
rename from streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestDomainPropertyMatch.java
rename to streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestSemanticTypeMatch.java
index 07038bd632..12d004b996 100644
--- a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestDomainPropertyMatch.java
+++ b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/matching/v2/TestSemanticTypeMatch.java
@@ -24,37 +24,32 @@ import org.apache.streampipes.vocabulary.Geo;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
-public class TestDomainPropertyMatch {
+public class TestSemanticTypeMatch {
 
   @Test
-  public void testPositiveDomainPropertyMatch() {
+  public void testPositiveSemanticTypeMatch() {
 
-    List<URI> offeredDomainProperty = buildDomainProperties(Geo.LAT);
-    List<URI> requiredDomainProperty = buildDomainProperties(Geo.LAT);
+    var offeredDomainProperty = Geo.LAT;
+    var requiredDomainProperty = Geo.LAT;
 
     List<MatchingResultMessage> resultMessage = new ArrayList<>();
 
-    boolean matches = new DomainPropertyMatch().match(offeredDomainProperty, requiredDomainProperty, resultMessage);
+    boolean matches = new SemanticTypeMatch().match(offeredDomainProperty, requiredDomainProperty, resultMessage);
     Assertions.assertTrue(matches);
   }
 
   @Test
-  public void testNegativeDomainPropertyMatch() {
+  public void testNegativeSemanticTypeMatch() {
 
-    List<URI> offeredDomainProperty = buildDomainProperties(Geo.LAT);
-    List<URI> requiredDomainProperty = buildDomainProperties(Geo.LNG);
+    var offeredDomainProperty = Geo.LAT;
+    var requiredDomainProperty = Geo.LNG;
 
     List<MatchingResultMessage> resultMessage = new ArrayList<>();
 
-    boolean matches = new DomainPropertyMatch().match(offeredDomainProperty, requiredDomainProperty, resultMessage);
+    boolean matches = new SemanticTypeMatch().match(offeredDomainProperty, requiredDomainProperty, resultMessage);
     Assertions.assertFalse(matches);
   }
-
-  private List<URI> buildDomainProperties(String name) {
-    return List.of(URI.create(name));
-  }
 }
diff --git a/streampipes-sdk/src/test/java/org/apache/streampipes/sdk/helpers/FiletypesTest.java b/streampipes-sdk/src/test/java/org/apache/streampipes/sdk/helpers/FiletypesTest.java
index 8c287f2cbc..2e0204fb53 100644
--- a/streampipes-sdk/src/test/java/org/apache/streampipes/sdk/helpers/FiletypesTest.java
+++ b/streampipes-sdk/src/test/java/org/apache/streampipes/sdk/helpers/FiletypesTest.java
@@ -29,9 +29,9 @@ class FiletypesTest {
   public void getAllFileExtensions_returnsAllExtensions() {
     var actualExtensions = Filetypes.getAllFileExtensions();
 
-    assertEquals(8, actualExtensions.size());
+    assertEquals(10, actualExtensions.size());
     assertTrue(actualExtensions.contains("jpg"));
     assertTrue(actualExtensions.contains("jpeg"));
     assertTrue(actualExtensions.contains("csv"));
   }
-}
\ No newline at end of file
+}
diff --git a/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventPropertyPrimitiveTestBuilder.java b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventPropertyPrimitiveTestBuilder.java
index fc5c1babc3..61439a9638 100644
--- a/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventPropertyPrimitiveTestBuilder.java
+++ b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventPropertyPrimitiveTestBuilder.java
@@ -21,7 +21,6 @@ import org.apache.streampipes.model.schema.EventPropertyPrimitive;
 import org.apache.streampipes.model.schema.PropertyScope;
 
 import java.net.URI;
-import java.util.List;
 
 public class EventPropertyPrimitiveTestBuilder
     extends EventPropertyTestBuilder<EventPropertyPrimitive, EventPropertyPrimitiveTestBuilder> {
@@ -41,7 +40,7 @@ public class EventPropertyPrimitiveTestBuilder
   }
 
   public EventPropertyPrimitiveTestBuilder withSemanticType(String semanticType) {
-    this.eventProperty.setDomainProperties(List.of(URI.create(semanticType)));
+    this.eventProperty.setSemanticType(semanticType);
     return this;
   }
 
diff --git a/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventStreamGenerator.java b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventStreamGenerator.java
index 97e420af86..e46e0ee1b8 100644
--- a/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventStreamGenerator.java
+++ b/streampipes-test-utils/src/main/java/org/apache/streampipes/test/generator/EventStreamGenerator.java
@@ -23,7 +23,6 @@ import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.test.generator.grounding.EventGroundingGenerator;
 import org.apache.streampipes.vocabulary.XSD;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -43,7 +42,7 @@ public class EventStreamGenerator {
         .getEventSchema()
         .setEventProperties(runtimeNames
             .stream()
-            .map(r -> new EventPropertyPrimitive(XSD.INTEGER.toString(), r, "", new ArrayList<>()))
+            .map(r -> new EventPropertyPrimitive(XSD.INTEGER.toString(), r, "", ""))
             .collect(Collectors.toList()));
 
     return stream;