/* * Copyright (C) 2015 RankSys http://ranksys.org * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.ranksys.compression.preferences; import es.uam.eps.ir.ranksys.core.preference.IdPref; import es.uam.eps.ir.ranksys.fast.index.FastItemIndex; import es.uam.eps.ir.ranksys.fast.index.FastUserIndex; import es.uam.eps.ir.ranksys.fast.preference.FastPreferenceData; import es.uam.eps.ir.ranksys.fast.preference.IdxPref; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntIterators; import org.ranksys.compression.codecs.CODEC; import org.ranksys.core.util.iterators.ArrayIntIterator; import java.io.Serializable; import java.util.function.Function; import java.util.stream.IntStream; import static java.util.stream.IntStream.of; import static java.util.stream.IntStream.range; import static org.ranksys.compression.util.Delta.atled; import org.ranksys.fast.preference.IteratorsAbstractFastPreferenceData; /** * Abstract PreferenceData using compression. * <br> * If you use this code, please cite the following papers: * <ul> * <li>Vargas, S., Macdonald, C., Ounis, I. (2015). Analysing Compression Techniques for In-Memory Collaborative Filtering. In Poster Proceedings of the 9th ACM Conference on Recommender Systems. <a href="http://ceur-ws.org/Vol-1441/recsys2015_poster2.pdf">http://ceur-ws.org/Vol-1441/recsys2015_poster2.pdf</a>.</li> * <li>Catena, M., Macdonald, C., Ounis, I. (2014). On Inverted Index Compression for Search Engine Efficiency. In ECIR (pp. 359–371). doi:10.1007/978-3-319-06028-6_30</li> * </ul> * The code that reproduces the results of the RecSys 2015 poster by Vargas et al. in a separated project: <a href="http://github.com/saulvargas/recsys2015">http://github.com/saulvargas/recsys2015</a> * <br> * The search index compression technologies of the ECIR paper by Catena et al. is part of the Terrier IR Platform: <a href="http://terrier.org/docs/v4.0/compression.html">http://terrier.org/docs/v4.0/compression.html</a>. * * @param <U> type of users * @param <I> type of items * @param <Cu> coding for user identifiers * @param <Ci> coding for item identifiers * @author Saúl Vargas (Saul.Vargas@glasgow.ac.uk) */ public abstract class AbstractCODECPreferenceData<U, I, Cu, Ci> extends IteratorsAbstractFastPreferenceData<U, I> implements FastPreferenceData<U, I> { /** * CODEC for user preferences. */ protected final CODEC<Cu> u_codec; /** * CODEC for item preferences. */ protected final CODEC<Ci> i_codec; /** * lists of items for users. */ protected final Cu[] u_idxs; /** * lengths of user preferences lists. */ protected final int[] u_len; /** * list of users for items. */ protected final Ci[] i_idxs; /** * lengths of item preferences lists. */ protected final int[] i_len; /** * Constructor with default IdxPref to IdPref converters. * * @param users user index * @param items item index * @param u_codec user preferences CODEC * @param i_codec item preferences CODEC */ @SuppressWarnings("unchecked") protected AbstractCODECPreferenceData(FastUserIndex<U> users, FastItemIndex<I> items, CODEC<Cu> u_codec, CODEC<Ci> i_codec) { this(users, items, u_codec, i_codec, (Function<IdxPref, IdPref<I>> & Serializable) p -> new IdPref<>(items.iidx2item(p)), (Function<IdxPref, IdPref<U>> & Serializable) p -> new IdPref<>(users.uidx2user(p))); } /** * Constructor with custom IdxPref to IdPref converters. * * @param users user index * @param items item index * @param u_codec user preferences CODEC * @param i_codec item preferences CODEC * @param uPrefFun user IdxPref to IdPref converter * @param iPrefFun item IdxPref to IdPref converter */ @SuppressWarnings("unchecked") protected AbstractCODECPreferenceData(FastUserIndex<U> users, FastItemIndex<I> items, CODEC<Cu> u_codec, CODEC<Ci> i_codec, Function<IdxPref, IdPref<I>> uPrefFun, Function<IdxPref, IdPref<U>> iPrefFun) { super(users, items, uPrefFun, iPrefFun); this.u_codec = u_codec; this.i_codec = i_codec; this.u_idxs = (Cu[]) new Object[users.numUsers()]; this.u_len = new int[users.numUsers()]; this.i_idxs = (Ci[]) new Object[items.numItems()]; this.i_len = new int[items.numItems()]; } @Override public int numUsers(int iidx) { return i_len[iidx]; } @Override public int numItems(int uidx) { return u_len[uidx]; } @Override public int numPreferences() { return of(u_len).sum(); } @Override public IntStream getUidxWithPreferences() { return range(0, u_len.length).filter(uidx -> u_len[uidx] > 0); } @Override public IntStream getIidxWithPreferences() { return range(0, i_len.length).filter(iidx -> i_len[iidx] > 0); } @Override public IntIterator getUidxIidxs(final int uidx) { return getIdx(u_idxs[uidx], u_len[uidx], u_codec); } @Override public IntIterator getIidxUidxs(final int iidx) { return getIdx(i_idxs[iidx], i_len[iidx], i_codec); } private static <Cx> IntIterator getIdx(Cx cidxs, int len, CODEC<Cx> x_codec) { if (len == 0) { return IntIterators.EMPTY_ITERATOR; } int[] idxs = new int[len]; x_codec.dec(cidxs, idxs, 0, len); if (!x_codec.isIntegrated()) { atled(idxs, 0, len); } return new ArrayIntIterator(idxs); } }