// TablesColumnIndex.java // (C) 2012 by Stefan Foerster, sof@gmx.de, Norderstedt, Germany // first published 2012 on http://yacy.net // // This is a part of YaCy, a peer-to-peer based web search engine // // LICENSE // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package net.yacy.kelondro.blob; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.yacy.cora.document.encoding.UTF8; import net.yacy.cora.order.NaturalOrder; /** * a mapping from a column name to maps with the value of the columns to the primary keys where the entry exist in the table */ public abstract class TablesColumnIndex { public static enum INDEXTYPE {RAM, BLOB} private INDEXTYPE type; // Map<ColumnName, Map<ColumnValue, T<PrimaryKey>>> // private final Map<String, Map<String, TreeSet<byte[]>>> index; protected final static Comparator<byte[]> NATURALORDER = new NaturalOrder(true); protected abstract void insertPK(final String columnName, final String columnValue, final byte[] pk); protected abstract void removePK(final byte[] pk); protected abstract void clear(); public abstract Set<String> keySet(final String columnName); public abstract boolean containsKey(final String columnName, final String key); public abstract boolean hasIndex(final String columnName); public abstract Collection<byte[]> get(final String columnName, final String key); public abstract int size(final String columnName); public abstract int size(); public abstract Collection<String> columns(); public abstract void deleteIndex(final String columnName); public TablesColumnIndex(INDEXTYPE type) { this.type = type; } public INDEXTYPE getType() { return this.type; } /** * create an index for a given table and given columns * @param columns - a map of column names and booleans for 'valueIsArray' you want to build an index for * @param separator - a string value used to split column values into an array * @param table - an iterator over table rows which should be added to the index */ public synchronized void buildIndex(final Map<String,String> columns, final Iterator<Tables.Row> table) { this.clear(); // loop through all rows of the table while (table.hasNext()) { this.add(columns, table.next()); } } private void insertPK(final String columnName, final String[] columnValues, final byte[] pk) { for (String columnValue : columnValues) { this.insertPK(columnName, columnValue, pk); } } public void delete(final byte[] pk) { this.removePK(pk); } public void update(final String columnName, final String separator, final Tables.Row row) { this.removePK(row.getPK()); this.add(columnName, separator, row); } public void update(final Map<String,String> columns, final Tables.Row row) { this.removePK(row.getPK()); this.add(columns, row); } public void add(final String columnName, final String separator, final Map<String,String> map, final byte[] pk) { if(separator.isEmpty()) this.insertPK(columnName, map.get(columnName), pk); else this.insertPK(columnName, map.get(columnName).split(separator), pk); } public void add(final String columnName, final String separator, final Tables.Data row, final byte[] pk) { if(separator.isEmpty()) this.insertPK(columnName, UTF8.String(row.get(columnName)), pk); else this.insertPK(columnName, UTF8.String(row.get(columnName)).split(separator), pk); } public void add(final String columnName, final String separator, final Tables.Row row) { if(separator.isEmpty()) this.insertPK(columnName, UTF8.String(row.get(columnName)), row.getPK()); else this.insertPK(columnName, UTF8.String(row.get(columnName)).split(separator), row.getPK()); } public void add(final Map<String,String> columns, final Map<String,String> map, final byte[] pk) { final Iterator<String> iter = columns.keySet().iterator(); while (iter.hasNext()) { final String columnName = iter.next(); if(columns.get(columnName).isEmpty()) this.insertPK(columnName, map.get(columnName), pk); else this.insertPK(columnName, map.get(columnName).split(columns.get(columnName)), pk); } } public void add(final Map<String,String> columns, final Tables.Data row, final byte[] pk) { final Iterator<String> iter = columns.keySet().iterator(); while (iter.hasNext()) { final String columnName = iter.next(); if(columns.get(columnName).isEmpty()) this.insertPK(columnName, UTF8.String(row.get(columnName)), pk); else this.insertPK(columnName, UTF8.String(row.get(columnName)).split(columns.get(columnName)), pk); } } public void add(final Map<String,String> columns, final Tables.Row row) { this.add(columns, row, row.getPK()); } }