Repository: apache/streampipes
Pull request #3239 (2024-09-18 02:55:42)

chore(deps): bump org.apache.commons:commons-compress from 1.26.0 to 1.27.1
Bumps org.apache.commons:commons-compress from 1.26.0 to 1.27.1.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.apache.commons:commons-compress&package-manager=maven&previous-version=1.26.0&new-version=1.27.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/osv-scanner.yml b/.github/workflows/osv-scanner.yml
index 7c1a2e231c..0d006f3c29 100644
--- a/.github/workflows/osv-scanner.yml
+++ b/.github/workflows/osv-scanner.yml
@@ -40,7 +40,7 @@ jobs:
 
       - name: Create Pull Request
         id: cpr
-        uses: peter-evans/create-pull-request@v6
+        uses: peter-evans/create-pull-request@v7
         with:
           token: ${{ secrets.GITHUB_TOKEN }}
           committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
diff --git a/installer/k8s/README.md b/installer/k8s/README.md
index 598e034ce9..48afd5a59e 100644
--- a/installer/k8s/README.md
+++ b/installer/k8s/README.md
@@ -78,8 +78,7 @@ ui-b94bd9766-rm6zb                             2/2     Running   0          3m27
 For **minikube users**:
 > **NOTE**: If you're running Docker Desktop or Minikube with a local k8s cluster, the above step to use your host IP
 > might not work. Luckily, you can port-forward a service port to your localhost using the following command to be able to
-> access the UI either via `http://localhost` or `http://<HOST_IP>` (you require sudo to run this command in order to bind
-> to a privileged port).
+> access the UI either via `http://localhost:8088` or `http://<HOST_IP>:8088` (If you want to use privileged ports such as 80, you need to run this command with sudo to bind to the privileged port).
 
 ```bash
 kubectl port-forward svc/ui --address=0.0.0.0 8088:8088
diff --git a/pom.xml b/pom.xml
index b5b52c3d1a..002b222bd9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,7 +47,7 @@
         <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-compress.version>1.27.1</commons-compress.version>
         <commons-io.version>2.16.1</commons-io.version>
         <commons-lang3.version>3.14.0</commons-lang3.version>
         <commons-logging.version>1.3.2</commons-logging.version>
@@ -105,7 +105,7 @@
         <plexus-interactivity-api.version>1.1</plexus-interactivity-api.version>
         <plexus-utils.version>4.0.0</plexus-utils.version>
         <postgresql.version>42.7.2</postgresql.version>
-        <protobuf.version>4.27.0</protobuf.version>
+        <protobuf.version>4.28.2</protobuf.version>
         <pulsar.version>3.2.2</pulsar.version>
         <quartz.version>2.3.2</quartz.version>
         <!-- needs to be lower than 4.x.x, see https://github.com/apache/streampipes/issues/1495 -->
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/.pre-commit-config.yaml b/streampipes-client-python/.pre-commit-config.yaml
index 04ccf3070c..e9ac86e307 100644
--- a/streampipes-client-python/.pre-commit-config.yaml
+++ b/streampipes-client-python/.pre-commit-config.yaml
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-files: streampipes/|tests/
+files: ^streampipes-client-python/(streampipes|tests)/
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
     rev: v4.6.0
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-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-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/dashboard/DashboardItem.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
index c7962b0411..81759642cb 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
@@ -18,6 +18,7 @@
 package org.apache.streampipes.model.dashboard;
 
 import java.util.List;
+import java.util.Map;
 
 public class DashboardItem {
 
@@ -31,6 +32,7 @@ public class DashboardItem {
   private Integer rows;
   private Integer x;
   private Integer y;
+  private Map<String, Object> timeSettings;
 
   public DashboardItem() {
 
@@ -99,4 +101,12 @@ public class DashboardItem {
   public void setY(Integer y) {
     this.y = y;
   }
+
+  public Map<String, Object> getTimeSettings() {
+    return timeSettings;
+  }
+
+  public void setTimeSettings(Map<String, Object> timeSettings) {
+    this.timeSettings = timeSettings;
+  }
 }
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-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-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/StreamPipesFunctionHandler.java b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/StreamPipesFunctionHandler.java
index aeda204da9..a36d788a4d 100644
--- a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/StreamPipesFunctionHandler.java
+++ b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/function/StreamPipesFunctionHandler.java
@@ -62,27 +62,32 @@ public enum StreamPipesFunctionHandler {
     var client = new StreamPipesClientResolver().makeStreamPipesClientInstance();
     functions.forEach(function -> {
       function.getFunctionConfig().getOutputDataStreams().values().forEach(ds -> {
-        DeclarersSingleton.getInstance().add(new IStreamPipesDataStream() {
-          @Override
-          public IDataStreamConfiguration declareConfig() {
-            return DataStreamConfiguration.create(
-                () -> this,
-                ds
-            );
+        if (!DeclarersSingleton.getInstance().getDataStreams().containsKey(ds.getAppId())) {
+          DeclarersSingleton.getInstance().add(new IStreamPipesDataStream() {
+            @Override
+            public IDataStreamConfiguration declareConfig() {
+              return DataStreamConfiguration.create(
+                  () -> this,
+                  ds
+              );
+            }
+
+            @Override
+            public void executeStream() {
+
+            }
+
+            @Override
+            public boolean isExecutable() {
+              return false;
+            }
+          });
+          if (client.streams().get(ds.getElementId()).isEmpty()) {
+            client.streams().create(ds);
+          } else {
+            client.streams().update(ds);
           }
-
-          @Override
-          public void executeStream() {
-
-          }
-
-          @Override
-          public boolean isExecutable() {
-            return false;
-          }
-        });
-
-        client.streams().create(ds);
+        }
       });
     });
   }
@@ -91,7 +96,7 @@ public enum StreamPipesFunctionHandler {
     this.runningInstances.forEach((key, value) -> {
       value.discardRuntime();
     });
-    new Thread(new FunctionDeregistrationHandler(getFunctionDefinitions())).start();
+    new FunctionDeregistrationHandler(getFunctionDefinitions()).run();
   }
 
   private List<FunctionDefinition> getFunctionDefinitions() {
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/.lintstagedrc.json b/ui/.lintstagedrc.json
index 059fea6ac0..ca7497c491 100644
--- a/ui/.lintstagedrc.json
+++ b/ui/.lintstagedrc.json
@@ -1,4 +1,4 @@
 {
-  "src/**/*.ts": "prettier --write",
-  "src/**/*.ts": ["ng-lint-staged lint --fix"]
+  "*.*": "prettier --check",
+  "src/**/*.ts": ["ng-lint-staged lint --"]
 }
diff --git a/ui/cypress/support/utils/datalake/DataLakeUtils.ts b/ui/cypress/support/utils/datalake/DataLakeUtils.ts
index de72c60baa..664c2ccd1c 100644
--- a/ui/cypress/support/utils/datalake/DataLakeUtils.ts
+++ b/ui/cypress/support/utils/datalake/DataLakeUtils.ts
@@ -91,7 +91,7 @@ export class DataLakeUtils {
         widgetType: string,
     ) {
         DataLakeUtils.goToDatalake();
-        DataLakeUtils.createAndEditDataView(dataViewName);
+        DataLakeUtils.createAndEditDataView();
 
         DataLakeUtils.selectTimeRange(
             new Date(2020, 10, 20, 22, 44),
@@ -162,7 +162,7 @@ export class DataLakeUtils {
 
     public static createAndEditDataView() {
         // Create new data view
-        cy.dataCy('open-new-data-view').click();
+        cy.dataCy('open-new-data-view', { timeout: 10000 }).click();
     }
 
     public static removeWidget(dataViewName: string) {
@@ -425,7 +425,7 @@ export class DataLakeUtils {
     }
 
     public static openTimeSelectorMenu() {
-        cy.dataCy('time-selector-menu').click();
+        cy.dataCy('time-selector-menu', { timeout: 10000 }).click();
     }
 
     public static applyCustomTimeSelection() {
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/dashboard/dashboard.model.ts b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
index 8a65f934ed..532a19b2d4 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts
@@ -25,6 +25,7 @@ export interface DashboardConfig extends GridsterConfig {}
 export interface ClientDashboardItem extends GridsterItem {
     widgetId: string;
     widgetType: string;
+    timeSettings?: TimeSettings;
     id: string;
 }
 
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DateRange.ts b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DateRange.ts
index 6c305f6dd4..9f3cff7d29 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/datalake/DateRange.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/datalake/DateRange.ts
@@ -24,6 +24,11 @@ export interface TimeSettings {
     timeSelectionId?: TimeSelectionId;
 }
 
+export interface WidgetTimeSettings {
+    timeSettings: TimeSettings;
+    widgetIndex?: number;
+}
+
 export interface TimeString {
     startDate: string;
     startTime: string;
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 7c9650ec20..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-10 17:11:03.
+// Generated using typescript-generator version 3.2.1263 on 2024-09-30 14:11:40.
 
 export class NamedStreamPipesEntity implements Storable {
     '@class':
@@ -970,6 +970,7 @@ export class DashboardItem {
     name: string;
     rows: number;
     settings: string[];
+    timeSettings: { [index: string]: any };
     x: number;
     y: number;
 
@@ -989,6 +990,9 @@ export class DashboardItem {
         instance.settings = __getCopyArrayFn(__identity<string>())(
             data.settings,
         );
+        instance.timeSettings = __getCopyObjectFn(__identity<any>())(
+            data.timeSettings,
+        );
         instance.x = data.x;
         instance.y = data.y;
         return instance;
@@ -1480,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,
@@ -1500,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/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-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.ts
index 8d0ff9d3b2..7c306ce446 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-runtime-resolvable-tree-input.component.ts
@@ -58,7 +58,17 @@ export class StaticRuntimeResolvableTreeInputComponent
     }
 
     ngOnInit(): void {
-        this.resetStaticPropertyState();
+        // if a node is selected it is assumed the adapter was opened in edit mode
+        // when that is the case, the browse tree should be reloaded
+        // if the adapter is created, the reload should only be triggered if all previous configurations are set correctly
+        if (
+            this.staticProperty.selectedNodesInternalNames &&
+            this.staticProperty.selectedNodesInternalNames.length > 0
+        ) {
+            this.resetStaticPropertyStateAndReload();
+        } else {
+            this.resetStaticPropertyState();
+        }
 
         if (
             this.staticProperty.nodes.length === 0 &&
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/components/time-selector/time-selector-menu/custom-time-range-selection/custom-time-range-selection.component.html b/ui/src/app/data-explorer/components/time-selector/time-selector-menu/custom-time-range-selection/custom-time-range-selection.component.html
index 9e277f0ca6..1564d9b5dc 100644
--- a/ui/src/app/data-explorer/components/time-selector/time-selector-menu/custom-time-range-selection/custom-time-range-selection.component.html
+++ b/ui/src/app/data-explorer/components/time-selector/time-selector-menu/custom-time-range-selection/custom-time-range-selection.component.html
@@ -74,6 +74,7 @@
         </div>
     </div>
     <div fxLayout="row" fxLayoutAlign="end center" class="mt-10">
+        <ng-content> </ng-content>
         <button
             mat-raised-button
             color="accent"
diff --git a/ui/src/app/data-explorer/components/time-selector/time-selector-menu/time-selector-menu.component.html b/ui/src/app/data-explorer/components/time-selector/time-selector-menu/time-selector-menu.component.html
index 70ded63676..e53550aa43 100644
--- a/ui/src/app/data-explorer/components/time-selector/time-selector-menu/time-selector-menu.component.html
+++ b/ui/src/app/data-explorer/components/time-selector/time-selector-menu/time-selector-menu.component.html
@@ -46,6 +46,7 @@
                     (timeSettingsEmitter)="timeSettingsEmitter.emit($event)"
                     class="w-100"
                 >
+                    <ng-content> </ng-content>
                 </sp-custom-time-range-selection>
             </div>
         </div>
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
index fa9617a0ed..ea476a9846 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
@@ -111,6 +111,34 @@
                 >
                     <mat-icon>get_app</mat-icon>
                 </button>
+                <button
+                    mat-icon-button
+                    [matMenuTriggerFor]="optMenu"
+                    *ngIf="!globalTimeEnabled"
+                    aria-label="Options"
+                    data-cy="options-data-explorer"
+                    #menuTrigger="matMenuTrigger"
+                >
+                    <mat-icon
+                        [color]="timeSettingsModified ? 'primary' : 'default'"
+                        >alarm_clock</mat-icon
+                    >
+                </button>
+                <mat-menu #optMenu="matMenu" class="large-menu">
+                    <sp-time-selector-menu
+                        [timeSettings]="clonedTimeSettings"
+                        (timeSettingsEmitter)="modifyWidgetTimeSettings($event)"
+                        class="w-100"
+                    >
+                        <button
+                            mat-raised-button
+                            class="mat-basic"
+                            (click)="resetWidgetTimeSettings()"
+                        >
+                            Reset
+                        </button>
+                    </sp-time-selector-menu>
+                </mat-menu>
                 <button
                     mat-icon-button
                     (click)="removeWidget()"
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
index 9e3e962de2..21e5170c0e 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
@@ -22,9 +22,11 @@ import {
     ComponentRef,
     EventEmitter,
     Input,
+    OnChanges,
     OnDestroy,
     OnInit,
     Output,
+    SimpleChanges,
     ViewChild,
 } from '@angular/core';
 import { GridsterItemComponent } from 'angular-gridster2';
@@ -45,13 +47,18 @@ import { UserPrivilege } from '../../../_enums/user-privilege.enum';
 import { CurrentUserService } from '@streampipes/shared-ui';
 import { BaseWidgetData } from '../../models/dataview-dashboard.model';
 import { DataExplorerDashboardService } from '../../services/data-explorer-dashboard.service';
+import { TimeSelectionService } from '../../services/time-selection.service';
+import { MatMenuTrigger } from '@angular/material/menu';
 
 @Component({
     selector: 'sp-data-explorer-dashboard-widget',
     templateUrl: './data-explorer-dashboard-widget.component.html',
     styleUrls: ['./data-explorer-dashboard-widget.component.scss'],
 })
-export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
+export class DataExplorerDashboardWidgetComponent
+    implements OnInit, OnDestroy, OnChanges
+{
+    @ViewChild('menuTrigger') menu: MatMenuTrigger;
     @Input()
     dashboardItem: DashboardItem;
 
@@ -97,6 +104,9 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
     timerActive = false;
     loadingTime = 0;
 
+    clonedTimeSettings: TimeSettings;
+    timeSettingsModified: boolean = false;
+
     hasDataExplorerWritePrivileges = false;
 
     authSubscription: Subscription;
@@ -116,8 +126,16 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
         private widgetTypeService: WidgetTypeService,
         private authService: AuthService,
         private currentUserService: CurrentUserService,
+        private timeSelectionService: TimeSelectionService,
     ) {}
 
+    ngOnChanges(changes: SimpleChanges): void {
+        if (changes.widgetIndex && this.componentRef?.instance) {
+            this.componentRef.instance.widgetIndex =
+                changes.widgetIndex.currentValue;
+        }
+    }
+
     ngOnInit(): void {
         this.authSubscription = this.currentUserService.user$.subscribe(
             user => {
@@ -139,6 +157,14 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
                 },
             );
         this.chooseWidget(this.configuredWidget.widgetType);
+        this.clonedTimeSettings = {
+            startTime: this.timeSettings.startTime,
+            endTime: this.timeSettings.endTime,
+            timeSelectionId: this.timeSettings.timeSelectionId,
+        };
+        if (this.dashboardItem.timeSettings !== undefined) {
+            this.timeSettingsModified = true;
+        }
     }
 
     ngOnDestroy() {
@@ -176,6 +202,7 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
         this.componentRef.instance.dataExplorerWidget = this.configuredWidget;
         this.componentRef.instance.previewMode = this.previewMode;
         this.componentRef.instance.gridMode = this.gridMode;
+        this.componentRef.instance.widgetIndex = this.widgetIndex;
         const removeSub =
             this.componentRef.instance.removeWidgetCallback.subscribe(ev =>
                 this.removeWidget(),
@@ -196,9 +223,13 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
     }
 
     getTimeSettings(): TimeSettings {
-        return this.globalTimeEnabled
-            ? this.timeSettings
-            : (this.configuredWidget.timeSettings as TimeSettings);
+        if (this.globalTimeEnabled) {
+            return this.timeSettings;
+        } else if (this.dashboardItem.timeSettings !== undefined) {
+            return this.dashboardItem.timeSettings as TimeSettings;
+        } else {
+            return this.configuredWidget.timeSettings as TimeSettings;
+        }
     }
 
     removeWidget() {
@@ -233,4 +264,26 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
             this.configuredWidget,
         );
     }
+
+    modifyWidgetTimeSettings(timeSettings: TimeSettings): void {
+        this.dashboardItem.timeSettings = timeSettings;
+        this.timeSelectionService.notify(timeSettings, this.widgetIndex);
+        this.menu.closeMenu();
+        this.timeSettingsModified = true;
+    }
+
+    resetWidgetTimeSettings(): void {
+        this.dashboardItem.timeSettings = undefined;
+        this.clonedTimeSettings = {
+            startTime: this.timeSettings.startTime,
+            endTime: this.timeSettings.endTime,
+            timeSelectionId: this.timeSettings.timeSelectionId,
+        };
+        this.timeSelectionService.notify(
+            this.getTimeSettings(),
+            this.widgetIndex,
+        );
+        this.menu.closeMenu();
+        this.timeSettingsModified = false;
+    }
 }
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
index b8e86ffdb9..5df627e9e7 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
@@ -83,6 +83,9 @@ export abstract class BaseDataExplorerWidgetDirective<
     @Input() dataViewDashboardItem: DashboardItem;
     @Input() dataExplorerWidget: T;
 
+    @Input()
+    widgetIndex: number;
+
     @HostBinding('class') className = 'h-100';
 
     public selectedProperties: string[];
@@ -193,16 +196,21 @@ export abstract class BaseDataExplorerWidgetDirective<
         }
         this.timeSelectionSub =
             this.timeSelectionService.timeSelectionChangeSubject.subscribe(
-                ts => {
-                    if (ts) {
-                        this.timeSettings = ts;
-                    } else {
-                        this.timeSelectionService.updateTimeSettings(
-                            this.timeSettings,
-                            new Date(),
-                        );
+                widgetTimeSettings => {
+                    if (
+                        widgetTimeSettings.widgetIndex === undefined ||
+                        widgetTimeSettings.widgetIndex === this.widgetIndex
+                    ) {
+                        if (widgetTimeSettings.timeSettings) {
+                            this.timeSettings = widgetTimeSettings.timeSettings;
+                        } else {
+                            this.timeSelectionService.updateTimeSettings(
+                                this.timeSettings,
+                                new Date(),
+                            );
+                        }
+                        this.updateData();
                     }
-                    this.updateData();
                 },
             );
         this.updateData();
diff --git a/ui/src/app/data-explorer/components/widgets/pie/config/pie-chart-widget-config.component.html b/ui/src/app/data-explorer/components/widgets/pie/config/pie-chart-widget-config.component.html
index a4f083aac8..b6b4b44d2e 100644
--- a/ui/src/app/data-explorer/components/widgets/pie/config/pie-chart-widget-config.component.html
+++ b/ui/src/app/data-explorer/components/widgets/pie/config/pie-chart-widget-config.component.html
@@ -77,11 +77,11 @@
                 <mat-slider min="0" max="80" step="1" fxFlex="65">
                     <input
                         matSliderThumb
-                        [(value)]="
+                        [ngModel]="
                             currentlyConfiguredWidget.visualizationConfig
                                 .selectedRadius
                         "
-                        (input)="updateInnerRadius($event.value)"
+                        (ngModelChange)="updateInnerRadius($event)"
                         #slider
                     />
                 </mat-slider>
diff --git a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-dashboard-dialog.component.html b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-dashboard-dialog.component.html
index de73ccaeff..98b4312145 100644
--- a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-dashboard-dialog.component.html
+++ b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-dashboard-dialog.component.html
@@ -67,7 +67,8 @@
                         [(ngModel)]="
                             dashboard.dashboardGeneralSettings.globalTimeEnabled
                         "
-                        >Use global time instead of widget time settings
+                        >Use global time settings instead of widget time
+                        settings
                     </mat-checkbox>
                 </div>
                 <!--<mat-checkbox [(ngModel)]="dashboard.displayHeader">Show name and description in dashboard</mat-checkbox>-->
diff --git a/ui/src/app/data-explorer/models/dataview-dashboard.model.ts b/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
index 670c73a29d..d3597f69db 100644
--- a/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
+++ b/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
@@ -54,6 +54,7 @@ export interface BaseWidgetData<T extends DataExplorerWidgetModel> {
     dataExplorerWidget: T;
     previewMode: boolean;
     gridMode: boolean;
+    widgetIndex?: number;
 
     cleanupSubscriptions(): void;
 }
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/data-explorer/services/time-selection.service.ts b/ui/src/app/data-explorer/services/time-selection.service.ts
index 11a9515cfc..5c55e7756a 100644
--- a/ui/src/app/data-explorer/services/time-selection.service.ts
+++ b/ui/src/app/data-explorer/services/time-selection.service.ts
@@ -23,6 +23,7 @@ import {
     QuickTimeSelection,
     TimeSelectionId,
     TimeSettings,
+    WidgetTimeSettings,
 } from '@streampipes/platform-services';
 import {
     startOfDay,
@@ -178,10 +179,11 @@ export class TimeSelectionService {
         }
     }
 
-    public timeSelectionChangeSubject: Subject<TimeSettings | undefined> =
-        new Subject<TimeSettings | undefined>();
+    public timeSelectionChangeSubject: Subject<WidgetTimeSettings | undefined> =
+        new Subject<WidgetTimeSettings | undefined>();
 
-    public notify(timeSettings?: TimeSettings): void {
-        this.timeSelectionChangeSubject.next(timeSettings);
+    public notify(timeSettings?: TimeSettings, widgetIndex?: number): void {
+        const widgetTimeSettings = { timeSettings, widgetIndex };
+        this.timeSelectionChangeSubject.next(widgetTimeSettings);
     }
 }
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();


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-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-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;
diff --git a/ui/cypress/tests/connect/opcua/startAndEditOpcAdapters.spec.ts b/ui/cypress/tests/connect/opcua/startAndEditOpcAdapters.spec.ts
index 0930395268..6e387b8958 100644
--- a/ui/cypress/tests/connect/opcua/startAndEditOpcAdapters.spec.ts
+++ b/ui/cypress/tests/connect/opcua/startAndEditOpcAdapters.spec.ts
@@ -51,13 +51,11 @@ describe('Test starting and editing OPC-UA Adapters in different configurations'
 
     it('Edit OPC-UA Adapter created with Tree editor', () => {
         const adapterInput = OpcUaUtils.getAdapterBuilderWithTreeNodes(true);
-
         editAdapterTest(adapterInput);
     });
 
     it('Edit OPC-UA Adapter created with Text editor', () => {
         const adapterInput = getAdapterBuilderWithTextNodes(true);
-
         editAdapterTest(adapterInput);
     });
 });
diff --git a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
index e2a8faff84..efecf9fc9b 100644
--- a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
+++ b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
@@ -44,11 +44,12 @@ describe('Test Time Range Selectors in Data Explorer', () => {
     before('Setup Tests', () => {
         cy.initStreamPipesTest();
         DataLakeUtils.loadDataIntoDataLake('datalake/sample.csv', false);
-        DataLakeUtils.goToDatalake();
-        DataLakeUtils.createAndEditDataView();
     });
 
     it('Perform Test', () => {
+        DataLakeUtils.goToDatalake();
+        DataLakeUtils.createAndEditDataView();
+
         periods.forEach(period => {
             cy.log('Testing period: ' + period.selector);
             DataLakeUtils.openTimeSelectorMenu();