org.apache.jena.propertytable.impl.PropertyTableHashMapImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-csv Show documentation
Show all versions of jena-csv Show documentation
jena-csv is for getting CSVs into a form that is amenable to Jena SPARQL processing, and doing so in a way that is not specific to CSV files. It includes getting the right architecture in place for regular table shaped data, using the core abstraction of PropertyTable.
The newest version!
/*
* 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.jena.propertytable.impl;
import java.util.* ;
import java.util.Map.Entry;
import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.atlas.iterator.IteratorConcat;
import org.apache.jena.ext.com.google.common.collect.HashMultimap;
import org.apache.jena.ext.com.google.common.collect.SetMultimap ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.propertytable.Column;
import org.apache.jena.propertytable.PropertyTable;
import org.apache.jena.propertytable.Row;
import org.apache.jena.util.iterator.ExtendedIterator ;
import org.apache.jena.util.iterator.NullIterator ;
import org.apache.jena.util.iterator.WrappedIterator ;
/**
* A PropertyTable Implementation using HashMap.
* It contains PSO and POS indexes.
*
*/
public class PropertyTableHashMapImpl implements PropertyTable {
private Map columnIndex; // Maps property Node key to Column
private List columnList; // Stores the list of columns in the table
private Map rowIndex; // Maps the subject Node key to Row.
private List rowList; // Stores the list of rows in the table
// PSO index
// Maps column Node to (subject Node, value) pairs
private Map> valueIndex;
// POS index
// Maps column Node to (value, subject Node) pairs
private Map> valueReverseIndex;
PropertyTableHashMapImpl() {
columnIndex = new HashMap();
columnList = new ArrayList();
rowIndex = new HashMap();
rowList = new ArrayList();
valueIndex = new HashMap>();
valueReverseIndex = new HashMap>();
}
@Override
public ExtendedIterator getTripleIterator() {
// use PSO index to scan all the table (slow)
IteratorConcat iter = new IteratorConcat();
for (Column column : getColumns()) {
iter.add(getTripleIterator(column));
}
return WrappedIterator.create(Iter.distinct(iter));
}
@Override
public ExtendedIterator getTripleIterator(Column column) {
// use PSO index directly (fast)
if (column == null || column.getColumnKey() == null)
throw new NullPointerException("column is null");
ArrayList triples = new ArrayList();
Map values = valueIndex.get(column.getColumnKey());
for (Entry entry : values.entrySet()) {
Node subject = entry.getKey();
Node value = entry.getValue();
triples.add(Triple.create(subject, column.getColumnKey(), value));
}
return WrappedIterator.create(triples.iterator());
}
@Override
public ExtendedIterator getTripleIterator(Node value) {
// use POS index ( O(n), n= column count )
if (value == null)
throw new NullPointerException("value is null");
IteratorConcat iter = new IteratorConcat();
for (Column column : this.getColumns()) {
ExtendedIterator eIter = getTripleIterator(column,value);
iter.add(eIter);
}
return WrappedIterator.create(Iter.distinct(iter));
}
@Override
public ExtendedIterator getTripleIterator(Column column, Node value) {
// use POS index directly (fast)
if (column == null || column.getColumnKey() == null)
throw new NullPointerException("column is null");
if (value == null)
throw new NullPointerException("value is null");
Node p = column.getColumnKey();
final SetMultimap valueToSubjectMap = valueReverseIndex.get(p);
if ( valueToSubjectMap == null )
return NullIterator.instance() ;
final Set subjects = valueToSubjectMap.get(value);
ArrayList triples = new ArrayList();
for (Node subject : subjects) {
triples.add(Triple.create(subject, p, value));
}
return WrappedIterator.create(triples.iterator());
}
@Override
public ExtendedIterator getTripleIterator(Row row) {
// use PSO index ( O(n), n= column count )
if (row == null || row.getRowKey() == null)
throw new NullPointerException("row is null");
ArrayList triples = new ArrayList();
for (Column column : getColumns()) {
Node value = row.getValue(column);
triples.add(Triple.create(row.getRowKey(), column.getColumnKey(), value));
}
return WrappedIterator.create(triples.iterator());
}
@Override
public Collection getColumns() {
return columnList;
}
@Override
public Column getColumn(Node p) {
if (p == null)
throw new NullPointerException("column node is null");
return columnIndex.get(p);
}
@Override
public Column createColumn(Node p) {
if (p == null)
throw new NullPointerException("column node is null");
if (columnIndex.containsKey(p))
throw new IllegalArgumentException("column already exists: '"
+ p.toString());
columnIndex.put(p, new ColumnImpl(this, p));
columnList.add(columnIndex.get(p));
valueIndex.put(p, new HashMap());
valueReverseIndex.put(p, HashMultimap.create());
return getColumn(p);
}
@Override
public Row getRow(final Node s) {
if (s == null)
throw new NullPointerException("subject node is null");
Row row = rowIndex.get(s);
return row;
}
@Override
public Row createRow(final Node s){
Row row = this.getRow(s);
if (row != null)
return row;
row = new InternalRow(s);
rowIndex.put(s, row);
rowList.add(row);
return row;
}
@Override
public List getAllRows() {
return rowList;
}
@Override
public List getColumnValues(Column column) {
if (column == null || column.getColumnKey() == null)
throw new NullPointerException("column is null");
Map values = valueIndex.get(column.getColumnKey());
List list = new ArrayList(values.size());
list.addAll(values.values());
return list;
}
@Override
public Collection getMatchingRows(Column column, Node value) {
if (column == null || column.getColumnKey() == null)
throw new NullPointerException("column is null");
if (value == null)
throw new NullPointerException("value is null");
Node p = column.getColumnKey();
final SetMultimap valueToSubjectMap = valueReverseIndex.get(p);
if ( valueToSubjectMap == null )
return Collections.emptyList() ;
final Set subjects = valueToSubjectMap.get(value);
if ( subjects == null )
return Collections.emptyList() ;
final ArrayList matchingRows = new ArrayList();
for (Node subject : subjects) {
matchingRows.add(this.getRow(subject));
}
return matchingRows;
}
private final void setX(final Node s, final Node p, final Node value) {
if (p == null)
throw new NullPointerException("column Node must not be null.");
if (value == null)
throw new NullPointerException("value must not be null.");
Map subjectToValueMap = valueIndex.get(p);
if (!columnIndex.containsKey(p) || subjectToValueMap == null)
throw new IllegalArgumentException("column: '" + p
+ "' does not yet exist.");
Node oldValue = subjectToValueMap.get(s);
subjectToValueMap.put(s, value);
addToReverseMap(p, s, oldValue, value);
}
private void addToReverseMap(final Node p, final Node s, final Node oldValue, final Node value) {
final SetMultimap valueToSubjectMap = valueReverseIndex.get(p);
if ( valueToSubjectMap == null )
return ;
valueToSubjectMap.remove(oldValue, s);
valueToSubjectMap.put(value, s);
}
private void unSetX(final Node s, final Node p) {
final Map subjectToValueMap = valueIndex.get(p);
if (!columnIndex.containsKey(p) || subjectToValueMap == null)
throw new IllegalArgumentException("column: '" + p
+ "' does not yet exist.");
final Node value = subjectToValueMap.get(s);
if (value == null)
return;
subjectToValueMap.remove(s);
removeFromReverseMap(p, s, value);
}
private void removeFromReverseMap(final Node p, final Node s,
final Node value) {
final SetMultimap valueTokeysMap = valueReverseIndex.get(p);
if ( valueTokeysMap == null )
return ;
valueTokeysMap.remove(s, value);
}
private Node getX(final Node s, final Node p) {
final Map subjectToValueMap = valueIndex.get(p);
if (!columnIndex.containsKey(p) || subjectToValueMap == null)
throw new IllegalArgumentException("column: '" + p
+ "' does not yet exist.");
return subjectToValueMap.get(s);
}
private final class InternalRow implements Row {
private final Node key;
InternalRow(final Node key) {
this.key = key;
}
@Override
public void setValue(Column column, Node value) {
if (value == null)
unSetX(key, column.getColumnKey());
else
setX(key, column.getColumnKey(), value);
}
@Override
public Node getValue(Column column) {
return getX(key, column.getColumnKey());
}
@Override
public Node getValue(Node columnKey) {
return getX(key, columnKey);
}
@Override
public PropertyTable getTable() {
return PropertyTableHashMapImpl.this;
}
@Override
public Node getRowKey() {
return key;
}
@Override
public Collection getColumns() {
// TODO Auto-generated method stub
return PropertyTableHashMapImpl.this.getColumns();
}
@Override
public ExtendedIterator getTripleIterator() {
ArrayList triples = new ArrayList();
for (Column column : getColumns()) {
Node value = this.getValue(column);
triples.add(Triple.create(key, column.getColumnKey(), value));
}
return WrappedIterator.create(triples.iterator());
}
}
}