Skip to content

Commit

Permalink
Add priority-based hierarchy builder and wizard (#403)
Browse files Browse the repository at this point in the history
* Initial implementation of priority-based hierarchy builder and wizard
  • Loading branch information
prasser authored Sep 14, 2022
1 parent fce74d8 commit ca3f9ee
Show file tree
Hide file tree
Showing 13 changed files with 999 additions and 40 deletions.
95 changes: 68 additions & 27 deletions src/example/org/deidentifier/arx/examples/Example18.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import org.deidentifier.arx.DataType;
import org.deidentifier.arx.aggregates.HierarchyBuilder;
import org.deidentifier.arx.aggregates.HierarchyBuilder.Type;
import org.deidentifier.arx.aggregates.HierarchyBuilderDate;
import org.deidentifier.arx.aggregates.HierarchyBuilderDate.Granularity;
import org.deidentifier.arx.aggregates.HierarchyBuilderGroupingBased.Level;
import org.deidentifier.arx.aggregates.HierarchyBuilderIntervalBased;
import org.deidentifier.arx.aggregates.HierarchyBuilderIntervalBased.Interval;
import org.deidentifier.arx.aggregates.HierarchyBuilderIntervalBased.Range;
import org.deidentifier.arx.aggregates.HierarchyBuilderPriorityBased.Priority;
import org.deidentifier.arx.aggregates.HierarchyBuilderOrderBased;
import org.deidentifier.arx.aggregates.HierarchyBuilderPriorityBased;
import org.deidentifier.arx.aggregates.HierarchyBuilderRedactionBased;
import org.deidentifier.arx.aggregates.HierarchyBuilderRedactionBased.Order;

Expand All @@ -43,7 +49,7 @@
* @author Florian Kohlmayer
*/
public class Example18 extends Example {

/**
* Entry point.
*
Expand All @@ -55,39 +61,36 @@ public static void main(String[] args) {
intervalBased();
orderBased();
ldlCholesterol();
dates();
date();
loadStore();
priorityBased();
}

/**
* Exemplifies the use of the order-based builder.
* Exemplifies the use of the date-based builder.
*/
private static void dates() {

private static void date() {
String stringDateFormat = "yyyy-MM-dd HH:mm";

DataType<Date> dateType = DataType.createDate(stringDateFormat);

// Create the builder
HierarchyBuilderOrderBased<Date> builder = HierarchyBuilderOrderBased.create(dateType, false);

// Define grouping fanouts
builder.getLevel(0).addGroup(10, dateType.createAggregate().createIntervalFunction());
builder.getLevel(1).addGroup(2, dateType.createAggregate().createIntervalFunction());

// Alternatively
// builder.setAggregateFunction(AggregateFunction.INTERVAL(DataType.INTEGER));
// builder.getLevel(0).addFanout(10);
// builder.getLevel(1).addFanout(2);
HierarchyBuilderDate builder = HierarchyBuilderDate.create(dateType);

// Define grouping
builder.setGranularities(new Granularity[] {Granularity.WEEK_YEAR,
Granularity.QUARTER_YEAR,
Granularity.YEAR});

System.out.println("---------------------");
System.out.println("ORDER-BASED DATE HIERARCHY");
System.out.println("DATE HIERARCHY");
System.out.println("---------------------");
System.out.println("");
System.out.println("SPECIFICATION");

// Print specification
for (Level<Date> level : builder.getLevels()) {
for (Granularity level : builder.getGranularities()) {
System.out.println(level);
}

Expand All @@ -101,7 +104,7 @@ private static void dates() {
printArray(builder.build().getHierarchy());
System.out.println("");
}

/**
* Returns example data.
*
Expand Down Expand Up @@ -134,6 +137,7 @@ private static String[] getExampleDateData(String stringFormat){

result[i] = format.format(date.getTime());
}
result[result.length - 1] = DataType.NULL_VALUE;
return result;
}

Expand All @@ -150,7 +154,7 @@ private static String[] getExampleLDLData() {
}
return result;
}

/**
* Exemplifies the use of the interval-based builder.
*/
Expand Down Expand Up @@ -199,7 +203,7 @@ private static void intervalBased() {
printArray(builder.build().getHierarchy());
System.out.println("");
}

/**
* Exemplifies the use of the interval-based builder for LDL cholesterol
* in mmol/l.
Expand Down Expand Up @@ -248,7 +252,7 @@ private static void ldlCholesterol() {
printArray(builder.build().getHierarchy());
System.out.println("");
}

/**
* Shows how to load and store hierarchy specifications.
*/
Expand Down Expand Up @@ -298,11 +302,6 @@ private static void orderBased() {
// Define grouping fanouts
builder.getLevel(0).addGroup(10, DataType.INTEGER.createAggregate().createIntervalFunction());
builder.getLevel(1).addGroup(2, DataType.INTEGER.createAggregate().createIntervalFunction());

// Alternatively
// builder.setAggregateFunction(AggregateFunction.INTERVAL(DataType.INTEGER));
// builder.getLevel(0).addFanout(10);
// builder.getLevel(1).addFanout(2);

System.out.println("---------------------");
System.out.println("ORDER-BASED HIERARCHY");
Expand All @@ -326,6 +325,48 @@ private static void orderBased() {
System.out.println("");
}

/**
* Exemplifies the use of the priority-based builder.
*/
private static void priorityBased() {

System.out.println("-------------------------");
System.out.println("PRIORITY-BASED HIERARCHY");
System.out.println("-------------------------");

// Data
String[] data = new String[] {"Prio1",
"Prio2",
"Prio3",
"Prio4",
"Prio5",
"Prio6",
"Prio7",
"Prio8",
"Prio9",
"Prio10",
"Prio11"};

Map<String, Integer> priorities = new HashMap<String, Integer>();
for (int i = 0; i < data.length; i++) {
priorities.put(data[i], -i);
}

// Create the builder
HierarchyBuilderPriorityBased<String> builder = HierarchyBuilderPriorityBased.create(priorities, Priority.HIGHEST_TO_LOWEST);
builder.setMaxLevels(3);

// Print info about resulting groups
System.out.println("Resulting levels: "+Arrays.toString(builder.prepare(data)));

System.out.println("");
System.out.println("RESULT");

// Print resulting hierarchy
printArray(builder.build().getHierarchy());
System.out.println("");
}

/**
* Exemplifies the use of the redaction-based builder.
*/
Expand Down
9 changes: 8 additions & 1 deletion src/gui/org/deidentifier/arx/gui/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.deidentifier.arx.DataType.DataTypeDescription;
import org.deidentifier.arx.RowSet;
import org.deidentifier.arx.aggregates.HierarchyBuilder;
import org.deidentifier.arx.aggregates.StatisticsFrequencyDistribution;
import org.deidentifier.arx.exceptions.RollbackRequiredException;
import org.deidentifier.arx.gui.model.Model;
import org.deidentifier.arx.gui.model.ModelAnonymizationConfiguration;
Expand Down Expand Up @@ -788,6 +789,12 @@ public void actionMenuEditCreateHierarchy() {
.getStatistics()
.getDistinctValues(index);

StatisticsFrequencyDistribution distribution = model.getInputConfig()
.getInput()
.getHandle()
.getStatistics()
.getFrequencyDistribution(index);

if (data.length == 1) {
main.showInfoDialog(main.getShell(),
Resources.getMessage("Controller.18"), //$NON-NLS-1$
Expand All @@ -797,7 +804,7 @@ public void actionMenuEditCreateHierarchy() {

HierarchyBuilder<?> builder = model.getInputConfig().getHierarchyBuilder(attr);
@SuppressWarnings({ "unchecked", "rawtypes" })
ARXWizard<HierarchyWizardResult<?>> wizard = new HierarchyWizard(this, attr, builder, type, model.getLocale(), data);
ARXWizard<HierarchyWizardResult<?>> wizard = new HierarchyWizard(this, attr, builder, type, model.getLocale(), data, distribution);

if (wizard.open(main.getShell())) {
HierarchyWizardResult<?> result = wizard.getResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,21 @@ HierarchyWizardPageRedaction.6=Mask characters left to right
HierarchyWizardPageRedaction.7=Mask characters right to left
HierarchyWizardPageRedaction.8=Characters
HierarchyWizardPageRedaction.9=Padding character
HierarchyWizardPagePriority.0=Create a hierarchy by prioritizing values
HierarchyWizardPagePriority.1=Specify the parameters
HierarchyWizardPagePriority.2=Prioritization
HierarchyWizardPagePriority.3=Prioritize by natural order (lowest to highest)
HierarchyWizardPagePriority.4=Prioritize by natural order (highest to lowest)
HierarchyWizardPagePriority.5=Prioritize by frequency (lowest to highest)
HierarchyWizardPagePriority.6=Prioritize by frequency (highest to lowest)
HierarchyWizardPagePriority.7=Maximal number of levels
HierarchyWizardPageType.0=Create a generalization hierarchy
HierarchyWizardPageType.1=Specify the type of hierarchy
HierarchyWizardPageType.2=Use intervals (for variables with ratio scale)
HierarchyWizardPageType.3=Use ordering (e.g., for variables with ordinal scale)
HierarchyWizardPageType.4=Use masking (e.g., for alphanumeric strings)
HierarchyWizardPageType.5=Use dates (for dates)
HierarchyWizardPageType.6=Use priorities (e.g., by frequency)
HierarchyWizardPageDate.0=Create a hierarchy for dates
HierarchyWizardPageDate.1=Specify the parameters
HierarchyWizardPageDate.2=Granularity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
package org.deidentifier.arx.gui.view.impl.wizard;

import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.deidentifier.arx.AttributeType.Hierarchy;
import org.deidentifier.arx.DataType;
Expand All @@ -28,6 +30,7 @@
import org.deidentifier.arx.aggregates.HierarchyBuilder.Type;
import org.deidentifier.arx.aggregates.HierarchyBuilderIntervalBased;
import org.deidentifier.arx.aggregates.HierarchyBuilderOrderBased;
import org.deidentifier.arx.aggregates.StatisticsFrequencyDistribution;
import org.deidentifier.arx.gui.Controller;
import org.deidentifier.arx.gui.resources.Resources;
import org.deidentifier.arx.gui.view.impl.wizard.ARXWizardDialog.ARXWizardButton;
Expand Down Expand Up @@ -110,6 +113,9 @@ public static interface HierarchyWizardView {
/** Var. */
private HierarchyWizardPageRedaction<T> pageRedaction;

/** Var. */
private HierarchyWizardPagePriority<T> pagePriority;

/** Var. */
private HierarchyWizardPageFinal<T> pageFinal;

Expand All @@ -125,18 +131,28 @@ public static interface HierarchyWizardView {
* @param datatype
* @param locale
* @param items
* @param distribution
*/
@SuppressWarnings("unchecked")
public HierarchyWizard(final Controller controller,
final String attribute,
final HierarchyBuilder<?> builder,
final DataType<T> datatype,
final Locale locale,
final String[] items) {
final String[] items,
final StatisticsFrequencyDistribution distribution) {
super(new Point(800, 400));

// Build frequency map
Map<String, Integer> frequency = new HashMap<>();
if (distribution != null) {
for (int i = 0; i < distribution.values.length; i++) {
frequency.put(distribution.values[i], (int)(distribution.frequency[i] * (double)distribution.count));
}
}

// Store
this.model = new HierarchyWizardModel<T>(datatype, locale, items);
this.model = new HierarchyWizardModel<T>(datatype, locale, items, frequency);
this.controller = controller;

// Parse given builder, if needed
Expand All @@ -146,7 +162,7 @@ public HierarchyWizard(final Controller controller,
}
} catch (Exception e){
/* Die silently, and recover*/
this.model = new HierarchyWizardModel<T>(datatype, locale, items);
this.model = new HierarchyWizardModel<T>(datatype, locale, items, frequency);
}

// Initialize window
Expand Down Expand Up @@ -192,7 +208,8 @@ public HierarchyWizard(final Controller controller,
}
pageOrder = new HierarchyWizardPageOrder<T>(controller, this, model, pageFinal);
pageRedaction = new HierarchyWizardPageRedaction<T>(controller, this, model, pageFinal);
pageType = new HierarchyWizardPageType<T>(this, model, pageIntervals, pageOrder, pageRedaction, pageDate);
pagePriority = new HierarchyWizardPagePriority<T>(controller, this, model, pageFinal);
pageType = new HierarchyWizardPageType<T>(this, model, pageIntervals, pageOrder, pageRedaction, pageDate, pagePriority);
}

@Override
Expand All @@ -201,6 +218,7 @@ public void addPages() {
addPage(pageType);
addPage(pageOrder);
addPage(pageRedaction);
addPage(pagePriority);
addPage(pageFinal);
if (pageIntervals != null) {
addPage(pageIntervals);
Expand Down Expand Up @@ -316,6 +334,12 @@ else if (builder.getType() == Type.DATE_BASED) {
this.pageType.updatePage();
this.getContainer().showPage(pageRedaction);
break;
case PRIORITY_BASED:
this.pagePriority.updatePage();
this.model.setType(Type.PRIORITY_BASED);
this.pageType.updatePage();
this.getContainer().showPage(pagePriority);
break;
}
}

Expand Down Expand Up @@ -344,6 +368,8 @@ private void save(){
builder = model.getIntervalModel().getBuilder(true);
} else if (getDialog().getCurrentPage() instanceof HierarchyWizardPageRedaction){
builder = model.getRedactionModel().getBuilder(true);
} else if (getDialog().getCurrentPage() instanceof HierarchyWizardPagePriority){
builder = model.getPriorityModel().getBuilder(true);
}

// Save
Expand Down
Loading

0 comments on commit ca3f9ee

Please sign in to comment.