Package com.guokr.simbase.engine

Source Code of com.guokr.simbase.engine.SimEngineImpl$SafeRunner

package com.guokr.simbase.engine;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.guokr.simbase.SimCall;
import com.guokr.simbase.SimCallback;
import com.guokr.simbase.SimContext;
import com.guokr.simbase.SimEngine;
import com.guokr.simbase.errors.SimEngineException;
import com.guokr.simbase.events.BasisListener;
import com.guokr.simbase.events.RecommendationListener;
import com.guokr.simbase.events.SimBasisListener;
import com.guokr.simbase.events.VectorSetListener;
import com.guokr.simbase.store.Basis;
import com.guokr.simbase.util.PrefixThreadFactory;

public class SimEngineImpl implements SimEngine, SimBasisListener {

    enum Kind {
        BASIS, VECTORS, RECOMM
    };

    private static final Logger logger = LoggerFactory.getLogger(SimEngineImpl.class);

    public abstract class AsyncSafeRunner implements Runnable {
        String scope;

        public AsyncSafeRunner(String scope) {
            this.scope = scope;
        }

        public abstract void invoke();

        @Override
        public void run() {
            try {
                invoke();
            } catch (Throwable ex) {
                logger.error(ex.getMessage(), ex);
            }
        }
    }

    public abstract class SafeRunner implements Runnable {
        SimCallback callback;
        String      scope;

        public SafeRunner(String scope, SimCallback callback) {
            this.scope = scope;
            this.callback = callback;
        }

        public abstract void invoke();

        @Override
        public void run() {
            try {
                invoke();
            } catch (Throwable ex) {
                String errMsg = ex.getMessage();
                logger.error(errMsg, ex);
                callback.error(errMsg);
            } finally {
                callback.response();
            }
        }
    }

    public class RejectedHandler implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            logger.error("server reject request");
        }

    }

    private SimContext                         context;

    private final ExecutorService              mngmExec    = Executors.newSingleThreadExecutor();
    private final Map<String, Kind>            kindOf      = new HashMap<String, Kind>();
    private final Map<String, String>          basisOf     = new HashMap<String, String>();
    private final Map<String, List<String>>    vectorsOf   = new HashMap<String, List<String>>();
    private final Map<String, Set<String>>     rtargetsOf  = new HashMap<String, Set<String>>();
    private final Map<String, SimBasis>        bases       = new HashMap<String, SimBasis>();

    private final Map<String, ExecutorService> writerExecs = new HashMap<String, ExecutorService>();
    private final ThreadPoolExecutor           readerPool  = new ThreadPoolExecutor(53, 83, 37, TimeUnit.SECONDS,
                                                                   new ArrayBlockingQueue<Runnable>(100),
                                                                   new PrefixThreadFactory("reader"),
                                                                   new RejectedHandler());

    private final Map<String, Integer>         counters    = new HashMap<String, Integer>();
    private final int                          bycount;
    private final String                       savePath;

    public SimEngineImpl(SimContext simContext) {
        String separator = System.getProperty("file.separator");
        this.context = simContext;
        this.bycount = simContext.getInt("bycount");
        this.savePath = new StringBuilder(System.getProperty("user.dir")).append(separator)
                .append(context.getString("savepath")).append(separator).toString();
        this.load(null);
        this.startCron();
    }

    private void validatePath(String filePath) throws SimEngineException {
        if (!new File(filePath).exists()) {
            throw new SimEngineException(String.format("Dmp file '%s' not exists", filePath));
        }
    }

    private void validateKeyFormat(String key) throws SimEngineException {
        if (key.indexOf('_') > -1) {
            throw new SimEngineException(String.format("Invalid key format '%s'", key));
        }
    }

    private void validateExistence(String toCheck) throws SimEngineException {
        if (!basisOf.containsKey(toCheck)) {
            throw new SimEngineException(String.format("Unknown data entry '%s'", toCheck));
        }
    }

    private void validateNotExistence(String toCheck) throws SimEngineException {
        if (basisOf.containsKey(toCheck)) {
            throw new SimEngineException(String.format("Data entry '%s' already exists", toCheck));
        }
    }

    private void validateKind(String op, String toCheck, Kind kindShouldBe) throws SimEngineException {
        if (!kindOf.containsKey(toCheck) || !kindShouldBe.equals(kindOf.get(toCheck))) {
            throw new SimEngineException(String.format("Operation '%s' against a non-%s type '%s'", op, kindShouldBe,
                    toCheck));
        }
    }

    private void validateId(int toCheck) throws SimEngineException {
        if (toCheck < 1) {
            throw new SimEngineException(String.format("Inviad id '%d', should be positive integer", toCheck));
        }
    }

    private void validatePairs(int maxIndex, int[] toCheck) throws SimEngineException {
        int len = toCheck.length;
        if (len % 2 != 0) {
            throw new SimEngineException("Sparse vector should be paired");
        }
        for (int offset = 0; offset < len; offset += 2) {
            if (toCheck[offset] < 0 || toCheck[offset] > maxIndex) {
                throw new SimEngineException(String.format("Sparse matrix index '%d' out of bound", toCheck[offset]));
            }
            if (toCheck[offset + 1] < 0) {
                throw new SimEngineException(String.format("Sparse matrix value '%d' should be non-negative",
                        toCheck[offset + 1]));
            }
        }
    }

    private void validateSameBasis(String vkeySource, String vkeyTarget) {
        if (!basisOf.get(vkeySource).equals(basisOf.get(vkeyTarget))) {
            throw new SimEngineException(String.format(
                    "Recommedation[%s_%s] must be between two vector set with same basis", vkeySource, vkeyTarget));
        }
    }

    private String rkey(String vkeySource, String vkeyTarget) {
        return new StringBuilder().append(vkeySource).append("_").append(vkeyTarget).toString();
    }

    public String[] info() {
        return new String[] { "version:" + version };
    }

    public void startCron() {
        final int saveInterval = this.context.getInt("saveinterval");

        Timer cron = new Timer();

        TimerTask savetask = new TimerTask() {
            public void run() {
                save(null);
            }
        };
        cron.schedule(savetask, saveInterval, saveInterval);
    }

    @Override
    @SimCall
    public void load(final SimCallback callback) {
        File[] files = new File(savePath).listFiles();
        for (File file : files) {
            String filename = file.getName();
            if (file.isFile() && filename.endsWith("dmp")) {
                bload(null, filename.replaceFirst("[.][^.]+$", ""));
            }
        }

        if (callback != null) {
            callback.ok();
            callback.response();
        }
    }

    @Override
    @SimCall
    public void save(final SimCallback callback) {
        for (String bkey : bases.keySet()) {
            bsave(null, bkey);
        }

        if (callback != null) {
            callback.ok();
            callback.response();
        }
    }

    @Override
    @SimCall
    public void del(final SimCallback callback, final String key) {
        validateExistence(key);
        writerExecs.get(basisOf.get(key)).execute(new AsyncSafeRunner("del") {
            @Override
            public void invoke() {
                delete(key);
            }

            public void delete(String toDel) {
                Kind kind = kindOf.get(toDel);
                switch (kind) {
                case BASIS:
                    if (vectorsOf.containsKey(toDel)) {
                        for (String vec : vectorsOf.get(toDel)) {
                            for (String source : rtargetsOf.keySet()) {
                                if (source.equals(vec)) {
                                    for (String target : rtargetsOf.get(vec)) {
                                        String recKey = rkey(vec, target);
                                        basisOf.remove(recKey);
                                        kindOf.remove(recKey);
                                    }
                                    rtargetsOf.remove(vec);
                                } else {
                                    rtargetsOf.get(source).remove(vec);
                                }
                            }
                            kindOf.remove(vec);
                            basisOf.remove(vec);
                        }
                    }
                    vectorsOf.remove(toDel);
                    kindOf.remove(toDel);
                    basisOf.remove(toDel);
                    bases.remove(toDel);
                    writerExecs.remove(toDel);
                    logger.info(String.format("basis[%s] deleted", toDel));
                    break;
                case VECTORS:
                    String bkey = basisOf.get(toDel);
                    for (String source : rtargetsOf.keySet()) {
                        if (source.equals(toDel)) {
                            for (String target : rtargetsOf.get(toDel)) {
                                delete(rkey(toDel, target));
                            }
                            rtargetsOf.remove(toDel);
                        } else {
                            rtargetsOf.get(source).remove(toDel);
                        }
                    }
                    vectorsOf.get(bkey).remove(toDel);
                    basisOf.remove(toDel);
                    kindOf.remove(toDel);
                    bases.get(bkey).vdel(toDel);
                    logger.info(String.format("vectorset[%s] deleted", toDel));
                    break;
                case RECOMM:
                    bases.get(basisOf.get(toDel)).rdel(toDel);
                    basisOf.remove(toDel);
                    kindOf.remove(toDel);
                    logger.info(String.format("recommendation[%s] deleted", toDel));
                    break;
                }
            }
        });

        if (callback != null) {
            callback.ok();
            callback.response();
        }
    }

    @Override
    @SimCall
    public void bload(final SimCallback callback, final String bkey) {
        mngmExec.execute(new AsyncSafeRunner("bload") {
            @Override
            public void invoke() {
                validateKeyFormat(bkey);
                String filePath = new StringBuilder(savePath).append(bkey).append(".dmp").toString();
                validatePath(filePath);
                if (basisOf.containsKey(bkey)) {
                    del(null, bkey);
                }

                logger.info(String.format("loading basis[%s]", bkey));

                Basis basis = new Basis(bkey);
                SimBasis simBasis = new SimBasis(context.getSub("basis", bkey), basis);
                bases.put(bkey, simBasis);
                basisOf.put(bkey, bkey);
                kindOf.put(bkey, Kind.BASIS);
                simBasis.addListener(SimEngineImpl.this);

                simBasis.bload(filePath);

                writerExecs.put(bkey, Executors.newSingleThreadExecutor());

                logger.info(String.format("basis[%s] loaded", bkey));
            }
        });

        if (callback != null) {
            callback.ok();
            callback.response();
        }
    }

    @Override
    @SimCall
    public void bsave(final SimCallback callback, final String bkey) {
        writerExecs.get(bkey).execute(new AsyncSafeRunner("bsave") {
            @Override
            public void invoke() {
                validateKind("bsave", bkey, Kind.BASIS);

                logger.info(String.format("saving basis[%s]", bkey));

                bases.get(bkey).bsave(new StringBuilder(savePath).append(bkey).append(".dmp").toString());

                logger.info(String.format("basis[%s] saved", bkey));
            }
        });

        if (callback != null) {
            callback.ok();
            callback.response();
        }
    }

    @Override
    @SimCall(callback = "S")
    public void blist(final SimCallback callback) {
        mngmExec.execute(new SafeRunner("blist", callback) {
            @Override
            public void invoke() {
                List<String> bkeys = new ArrayList<String>(bases.keySet());
                Collections.sort(bkeys);
                callback.stringList((String[]) bkeys.toArray(new String[bkeys.size()]));
            }
        });
    }

    @Override
    @SimCall
    public void bmk(final SimCallback callback, final String bkey, final String[] base) {
        mngmExec.execute(new SafeRunner("bmk", callback) {
            @Override
            public void invoke() {
                validateKeyFormat(bkey);
                validateNotExistence(bkey);
                Basis basis = new Basis(bkey, base);
                SimBasis simbasis = new SimBasis(context.getSub("basis", bkey), basis);
                bases.put(bkey, simbasis);
                basisOf.put(bkey, bkey);
                kindOf.put(bkey, Kind.BASIS);
                simbasis.addListener(SimEngineImpl.this);

                writerExecs.put(bkey, Executors.newSingleThreadExecutor());

                logger.info(String.format("basis[%s] created", bkey));

                callback.ok();
            }
        });
    }

    @Override
    @SimCall
    public void brev(final SimCallback callback, final String bkey, final String[] base) {
        writerExecs.get(bkey).execute(new SafeRunner("brev", callback) {
            @Override
            public void invoke() {
                validateKind("brev", bkey, Kind.BASIS);
                validateKeyFormat(bkey);
                bases.get(bkey).brev(base);

                logger.info(String.format("basis[%s] revised", bkey));

                callback.ok();
            }
        });
    }

    @Override
    @SimCall(callback = "S")
    public void bget(final SimCallback callback, final String bkey) {
        validateKind("bget", bkey, Kind.BASIS);
        readerPool.submit(new SafeRunner("bget", callback) {
            @Override
            public void invoke() {
                callback.stringList(bases.get(bkey).bget());
            }
        });
    }

    @Override
    @SimCall(callback = "S")
    public void vlist(final SimCallback callback, final String bkey) {
        mngmExec.execute(new SafeRunner("vlist", callback) {
            @Override
            public void invoke() {
                validateKind("vlist", bkey, Kind.BASIS);
                List<String> vkeys = vectorsOf.get(bkey);
                if (vkeys == null) {
                    vkeys = new ArrayList<String>();
                } else {
                    Collections.sort(vkeys);
                }
                int i = 0;
                String[] result = new String[vkeys.size()];
                for (String key : vkeys) {
                    result[i++] = key;
                }
                callback.stringList(result);
            }
        });
    }

    @Override
    @SimCall
    public void vmk(final SimCallback callback, final String bkey, final String vkey) {
        mngmExec.execute(new SafeRunner("vmk", callback) {
            @Override
            public void invoke() {
                validateKind("vmk", bkey, Kind.BASIS);
                validateKeyFormat(vkey);
                validateNotExistence(vkey);
                bases.get(bkey).vmk(vkey);

                kindOf.put(vkey, Kind.VECTORS);
                basisOf.put(vkey, bkey);
                List<String> vkeys = vectorsOf.get(bkey);
                if (vkeys == null) {
                    vkeys = new ArrayList<String>();
                    vectorsOf.put(bkey, vkeys);
                }
                vkeys.add(vkey);

                logger.info(String.format("vectorset[%s] created under basis[%s]", vkey, bkey));

                callback.ok();
            }
        });
    }

    @Override
    @SimCall(callback = "i")
    public void vlen(final SimCallback callback, final String vkey) {
        validateKind("vget", vkey, Kind.VECTORS);
        final String bkey = basisOf.get(vkey);
        readerPool.submit(new SafeRunner("vids", callback) {
            @Override
            public void invoke() {
                callback.integerValue(bases.get(bkey).vlen(vkey));
            }
        });
    }

    @Override
    @SimCall(callback = "I")
    public void vids(final SimCallback callback, final String vkey) {
        validateKind("vget", vkey, Kind.VECTORS);
        final String bkey = basisOf.get(vkey);
        readerPool.submit(new SafeRunner("vids", callback) {
            @Override
            public void invoke() {
                callback.integerList(bases.get(bkey).vids(vkey));
            }
        });
    }

    // CURD operations for one vector in vector-set

    @Override
    @SimCall(callback = "F")
    public void vget(final SimCallback callback, final String vkey, final int vecid) {
        validateKind("vget", vkey, Kind.VECTORS);
        final String bkey = basisOf.get(vkey);
        readerPool.submit(new SafeRunner("vget", callback) {
            @Override
            public void invoke() {
                callback.floatList(bases.get(bkey).vget(vkey, vecid));
            }
        });
    }

    @Override
    @SimCall
    public void vadd(final SimCallback callback, final String vkey, final int vecid, final float[] vector) {
        validateKind("vadd", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("vadd") {
            @Override
            public void invoke() {
                bases.get(bkey).vadd(vkey, vecid, vector);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("adding dense vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("vector[%s] added to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall
    public void vset(final SimCallback callback, final String vkey, final int vecid, final float[] vector) {
        validateKind("vset", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("vset") {
            @Override
            public void invoke() {
                bases.get(bkey).vset(vkey, vecid, vector);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("setting dense vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("vector[%s] setted to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall
    public void vacc(final SimCallback callback, final String vkey, final int vecid, final float[] vector) {
        validateKind("vacc", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("vacc") {
            @Override
            public void invoke() {
                bases.get(bkey).vacc(vkey, vecid, vector);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("acculmulating dense vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("vector[%s] accumulated to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall
    public void vrem(final SimCallback callback, final String vkey, final int vecid) {
        this.validateKind("vrem", vkey, Kind.VECTORS);
        final String bkey = basisOf.get(vkey);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("vrem") {
            @Override
            public void invoke() {
                bases.get(bkey).vrem(vkey, vecid);

                logger.info(String.format("vector[%s] removed from vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    // Internal use for client-side sparsification
    @Override
    @SimCall(callback = "I")
    public void iget(final SimCallback callback, final String vkey, final int vecid) {
        validateExistence(vkey);
        final String bkey = basisOf.get(vkey);
        readerPool.submit(new SafeRunner("iget", callback) {
            @Override
            public void invoke() {
                callback.integerList(bases.get(bkey).iget(vkey, vecid));
            }
        });
    }

    @Override
    @SimCall
    public void iadd(SimCallback callback, final String vkey, final int vecid, final int[] pairs) {
        validateKind("iadd", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        int maxIndex = bases.get(bkey).bget().length;
        validatePairs(maxIndex, pairs);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("iadd") {
            @Override
            public void invoke() {
                bases.get(bkey).iadd(vkey, vecid, pairs);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("adding sparse vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("sparse vector[%s] added to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall
    public void iset(final SimCallback callback, final String vkey, final int vecid, final int[] pairs) {
        validateKind("iset", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        int maxIndex = bases.get(bkey).bget().length;
        validatePairs(maxIndex, pairs);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("iset") {
            @Override
            public void invoke() {
                bases.get(bkey).iset(vkey, vecid, pairs);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("setting sparse vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("sparse vector[%s] setted to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall
    public void iacc(final SimCallback callback, final String vkey, final int vecid, final int[] pairs) {
        this.validateKind("iacc", vkey, Kind.VECTORS);
        validateId(vecid);
        final String bkey = basisOf.get(vkey);
        int maxIndex = bases.get(bkey).bget().length;
        validatePairs(maxIndex, pairs);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("iacc") {
            @Override
            public void invoke() {
                bases.get(bkey).iacc(vkey, vecid, pairs);

                if (!counters.containsKey(vkey)) {
                    counters.put(vkey, 0);
                }
                int counter = counters.get(vkey) + 1;
                counters.put(vkey, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("accumulating sparse vectors %d to %s", counter, vkey));
                }
                logger.info(String.format("sparse vector[%s] accumulated to vectorset[%s]", vecid, vkey));
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall(callback = "S")
    public void rlist(final SimCallback callback, final String vkey) {
        mngmExec.execute(new SafeRunner("rlist", callback) {
            @Override
            public void invoke() {
                validateKind("rlist", vkey, Kind.VECTORS);
                List<String> targets = new ArrayList<String>();
                Set<String> tgtSet = rtargetsOf.get(vkey);
                if (tgtSet != null) {
                    targets.addAll(tgtSet);
                    Collections.sort(targets);
                }
                callback.stringList((String[]) targets.toArray(new String[targets.size()]));
            }
        });
    }

    @Override
    @SimCall
    public void rmk(final SimCallback callback, final String vkeySource, final String vkeyTarget, final String funcscore) {
        validateSameBasis(vkeySource, vkeyTarget);
        final String bkey = basisOf.get(vkeySource);
        writerExecs.get(bkey).execute(new SafeRunner("rmk", callback) {
            @Override
            public void invoke() {
                validateKind("rmk", vkeySource, Kind.VECTORS);
                validateKind("rmk", vkeyTarget, Kind.VECTORS);
                validateSameBasis(vkeyTarget, vkeySource);
                String rkey = rkey(vkeySource, vkeyTarget);
                validateNotExistence(rkey);

                logger.info(String.format("creating recommendation[%s_%s] with funcscore[%s]", vkeySource, vkeyTarget,
                        funcscore));

                final String bkey = basisOf.get(vkeySource);
                bases.get(bkey).rmk(vkeySource, vkeyTarget, funcscore);
                basisOf.put(rkey, basisOf.get(vkeySource));
                kindOf.put(rkey, Kind.RECOMM);

                if (rtargetsOf.get(vkeySource) == null) {
                    rtargetsOf.put(vkeySource, new HashSet<String>());
                }
                rtargetsOf.get(vkeySource).add(vkeyTarget);

                logger.info(String.format("recommendation[%s_%s] created with funcscore[%s]", vkeySource, vkeyTarget,
                        funcscore));

                callback.ok();
            }
        });
    }

    @Override
    @SimCall(callback = "S")
    public void rget(final SimCallback callback, final String vkeySource, final int vecid, final String vkeyTarget) {
        validateKind("rget", vkeySource, Kind.VECTORS);
        validateKind("rget", vkeyTarget, Kind.VECTORS);
        String rkey = rkey(vkeySource, vkeyTarget);
        validateExistence(rkey);
        final String bkey = basisOf.get(vkeySource);
        readerPool.submit(new SafeRunner("rget", callback) {
            @Override
            public void invoke() {
                callback.stringList(bases.get(bkey).rget(vkeySource, vecid, vkeyTarget));
            }
        });
    }

    @Override
    @SimCall(callback = "I")
    public void rrec(final SimCallback callback, final String vkeySource, final int vecid, final String vkeyTarget) {
        validateKind("rget", vkeySource, Kind.VECTORS);
        validateKind("rget", vkeyTarget, Kind.VECTORS);
        String rkey = rkey(vkeySource, vkeyTarget);
        validateExistence(rkey);
        final String bkey = basisOf.get(vkeySource);
        readerPool.submit(new SafeRunner("rrec", callback) {
            @Override
            public void invoke() {
                callback.integerList(bases.get(bkey).rrec(vkeySource, vecid, vkeyTarget));
            }
        });
    }

    @Override
    @SimCall
    public void xacc(SimCallback callback, final String vkeyTarget, final int vecidTarget, final String vkeyOperand,
            final int vecidOperand) {
        validateKind("xacc", vkeyTarget, Kind.VECTORS);
        validateId(vecidTarget);
        validateKind("xacc", vkeyOperand, Kind.VECTORS);
        validateId(vecidOperand);
        final String bkey = basisOf.get(vkeyTarget);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("xacc") {
            @Override
            public void invoke() {
                SimBasis base = bases.get(bkey);
                float[] vector = base.vget(vkeyOperand, vecidOperand);
                base.vacc(vkeyTarget, vecidTarget, vector);

                if (!counters.containsKey(vkeyTarget)) {
                    counters.put(vkeyTarget, 0);
                }
                int counter = counters.get(vkeyTarget) + 1;
                counters.put(vkeyTarget, counter);
                if (counter % bycount == 0) {
                    logger.info(String.format("acculmulating dense vectors %d to %s", counter, vkeyTarget));
                }
            }
        });

        callback.ok();
        callback.response();
    }

    @Override
    @SimCall(callback = "F")
    public void xprd(final SimCallback callback, final String vkeyTarget, final int vecidTarget,
            final String vkeyOperand, final int[] vecidOperands) {
        validateKind("xprd", vkeyTarget, Kind.VECTORS);
        validateId(vecidTarget);
        validateKind("xprd", vkeyOperand, Kind.VECTORS);
        for (int vecidOperand : vecidOperands) {
            validateId(vecidOperand);
        }
        final String bkey = basisOf.get(vkeyTarget);
        writerExecs.get(bkey).execute(new AsyncSafeRunner("xprd") {
            @Override
            public void invoke() {
                SimBasis base = bases.get(bkey);

                int size = vecidOperands.length;
                float[] scores = new float[size];
                float[] target = base.vget(vkeyTarget, vecidTarget);
                for (int i = 0; i < size; i++) {
                    int vecidOperand = vecidOperands[i];
                    float[] operand = base.vget(vkeyOperand, vecidOperand);

                    int len = target.length;
                    float score = 0f, lensq1 = 0f, lensq2 = 0f;
                    for (int j = 0; j < len; j++) {
                        score += target[j] * operand[j];
                    }
                    for (int j = 0; j < len; j++) {
                        lensq1 += target[j] * target[j];
                    }
                    for (int j = 0; j < len; j++) {
                        lensq2 += operand[j] * operand[j];
                    }

                    if (lensq1 > 0 && lensq2 > 0) {
                        scores[i] = (float) (score / Math.sqrt(lensq1) / Math.sqrt(lensq2));
                    } else {
                        scores[i] = 0f;
                    }
                }

                callback.floatList(scores);
                callback.response();
            }
        });
    }

    @Override
    public void listen(final String bkey, final BasisListener listener) {
        writerExecs.get(bkey).execute(new Runnable() {
            @Override
            public void run() {
                bases.get(bkey).addListener(listener);
            }
        });
    }

    @Override
    public void listen(final String vkey, final VectorSetListener listener) {
        final String bkey = basisOf.get(vkey);
        writerExecs.get(bkey).execute(new Runnable() {
            @Override
            public void run() {
                bases.get(bkey).addListener(vkey, listener);
            }
        });
    }

    @Override
    public void listen(final String srcVkey, final String tgtVkey, final RecommendationListener listener) {
        final String bkey = basisOf.get(srcVkey);
        writerExecs.get(bkey).execute(new Runnable() {
            @Override
            public void run() {
                bases.get(bkey).addListener(srcVkey, tgtVkey, listener);
            }
        });
    }

    @Override
    public void onVecSetAdded(String bkeySrc, String vkey) {
        basisOf.put(vkey, bkeySrc);

        List<String> vecs = vectorsOf.get(bkeySrc);
        if (vecs == null) {
            vecs = new ArrayList<String>();
            vectorsOf.put(bkeySrc, vecs);
        }
        vecs.add(vkey);

        kindOf.put(vkey, Kind.VECTORS);
    }

    @Override
    public void onVecSetDeleted(String bkeySrc, String vkey) {
        basisOf.remove(vkey);
        vectorsOf.get(bkeySrc).remove(vkey);
        kindOf.remove(vkey);
    }

    @Override
    public void onRecAdded(String bkeySrc, String vkeyFrom, String vkeyTo) {
        String rkey = rkey(vkeyFrom, vkeyTo);

        basisOf.put(rkey, bkeySrc);

        Set<String> tgt = rtargetsOf.get(vkeyFrom);
        if (tgt == null) {
            tgt = new HashSet<String>();
            rtargetsOf.put(vkeyFrom, tgt);
        }
        tgt.add(vkeyTo);

        kindOf.put(rkey, Kind.RECOMM);
    }

    @Override
    public void onRecDeleted(String bkeySrc, String vkeyFrom, String vkeyTo) {
        String rkey = rkey(vkeyFrom, vkeyTo);
        basisOf.remove(rkey);
        rtargetsOf.get(vkeyFrom).remove(vkeyTo);
        kindOf.remove(rkey);
    }

}
TOP

Related Classes of com.guokr.simbase.engine.SimEngineImpl$SafeRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
d', 'pageview');