All Downloads are FREE. Search and download functionalities are using the official Maven repository.

angry1980.audio.service.TrackSimilarityServiceImpl Maven / Gradle / Ivy

There is a newer version: 0.0.10
Show newest version
package angry1980.audio.service;

import angry1980.audio.dao.TrackDAO;
import angry1980.audio.dao.TrackSimilarityDAO;
import angry1980.audio.model.FingerprintType;
import angry1980.audio.model.Track;
import angry1980.audio.model.TrackSimilarity;
import angry1980.audio.similarity.FindSimilarTracks;
import angry1980.audio.similarity.TrackSimilarities;
import angry1980.audio.similarity.TracksToCalculate;
import angry1980.utils.ImmutableCollectors;
import it.unimi.dsi.fastutil.longs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import rx.Observable;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

public class TrackSimilarityServiceImpl implements TrackSimilarityService {

    private static Logger LOG = LoggerFactory.getLogger(TrackSimilarityServiceImpl.class);

    private TrackDAO trackDAO;
    private TrackSimilarityDAO trackSimilarityDAO;
    private FindSimilarTracks findSimilarTracks;
    private TracksToCalculate tracksToCalculate;

    public TrackSimilarityServiceImpl(TrackDAO trackDAO,
                                      TrackSimilarityDAO trackSimilarityDAO,
                                      FindSimilarTracks findSimilarTracks,
                                      TracksToCalculate tracksToCalculate) {
        this.trackDAO = Objects.requireNonNull(trackDAO);
        this.trackSimilarityDAO = Objects.requireNonNull(trackSimilarityDAO);
        this.findSimilarTracks = Objects.requireNonNull(findSimilarTracks);
        this.tracksToCalculate = Objects.requireNonNull(tracksToCalculate);
    }

    @Override
    public Observable getTracksToCalculateSimilarity() {
        return tracksToCalculate.get();
    }

    @Override
    public Observable findOrCalculateSimilarities(Track track, FingerprintType type, FingerprintType ... types) {
        Observable r = Observable.just(type);
        if(types.length > 0){
            r = r.mergeWith(Observable.from(types));
        }
        return r
                .doOnNext(t -> LOG.debug("{} is getting ready to handle by {} implementation", track.getId(), t))
                .map(t -> findSimilarTracks.apply(track.getId(), t))
                .map(s -> {
                        LOG.debug("{} was handled. There are {} similarities. ", track.getId(), s.size());
                        return new TrackSimilarities(track, s);
                });
    }

    @Override
    public Observable getReport() {
        return Observable.create(subscriber -> {
            trackDAO.getAllOrEmpty().stream()
                    .map(track -> new TrackSimilarities(track, trackSimilarityDAO.findByTrackIdOrEmpty(track.getId())))
                    .forEach(subscriber::onNext);
            subscriber.onCompleted();
        });
    }

    @Override
    public Observable findSimilarities(FingerprintType fingerprintType, boolean truthPositive) {
        Supplier>> s = () -> truthPositive
                ? trackSimilarityDAO.findTruthPositiveByFingerprintType(fingerprintType)
                : trackSimilarityDAO.findFalsePositiveByFingerprintType(fingerprintType)
        ;
        return Observable.create(subscriber -> {
            s.get().orElseGet(Collections::emptyList)
                    .stream()
                    .filter(Objects::nonNull)
                    .forEach(subscriber::onNext)
            ;
            subscriber.onCompleted();
        });
    }

    @Override
    public Observable findCommonSimilarities(FingerprintType fingerprintType, boolean onlyTruthPositive) {
        Long2ObjectMap empty = new Long2ObjectArrayMap<>();
        Function>> f = t -> onlyTruthPositive
                                                ? trackSimilarityDAO.findTruthPositiveByFingerprintType(t)
                                                : trackSimilarityDAO.findByFingerprintType(t)
                                                //: trackSimilarityDAO.findFalsePositiveByFingerprintType(t)
        ;
        Long2ObjectMap> sorted = f.apply(fingerprintType)
                .map(this::sortByTracks)
                .orElseGet(Long2ObjectArrayMap::new);
        return Observable.create(subscriber -> {
            Arrays.stream(FingerprintType.values())
                    .filter(type -> !type.equals(fingerprintType))
                    .flatMap(type -> f.apply(type).orElseGet(Collections::emptyList).stream())
                    .map(ts -> sorted.getOrDefault(ts.getTrack1(), empty).get(ts.getTrack2()))
                    .filter(Objects::nonNull)
                    .forEach(subscriber::onNext)
            ;
            subscriber.onCompleted();
        });
    }

    @Override
    public Observable findUniqueSimilarities(FingerprintType fingerprintType, boolean onlyTruthPositive) {
        Long2ObjectMap empty = new Long2ObjectArrayMap<>();
        Function>> f = t -> onlyTruthPositive
                ? trackSimilarityDAO.findTruthPositiveByFingerprintType(t)
                //: trackSimilarityDAO.findByFingerprintType(t)
                : trackSimilarityDAO.findFalsePositiveByFingerprintType(t)
                ;
        Long2ObjectMap>[] sorted = Arrays.stream(FingerprintType.values())
                .filter(type -> !type.equals(fingerprintType))
                .map(type -> f.apply(type).map(this::sortByTracks).orElseGet(Long2ObjectArrayMap::new))
                .toArray(Long2ObjectMap[]::new);
        return Observable.create(subscriber -> {
            f.apply(fingerprintType).orElseGet(Collections::emptyList).stream()
                    .filter(ts -> {
                        for(Long2ObjectMap> s : sorted){
                            if(s.getOrDefault(ts.getTrack1(), empty).containsKey(ts.getTrack2())){
                                return false;
                            }
                        }
                        return true;
                    }).forEach(subscriber::onNext)
            ;
            subscriber.onCompleted();
        });

    }

    private Long2ObjectMap> sortByTracks(List list){
        return list.stream().collect(
                Collector.of(
                        () -> new Long2ObjectArrayMap>(),
                        (map, ts) -> map.computeIfAbsent(ts.getTrack1(), t1 -> new Long2ObjectArrayMap<>()).put(ts.getTrack2(), ts),
                        (map1, map2) -> {
                            map2.entrySet().stream()
                                    .filter(entry -> !CollectionUtils.isEmpty(entry.getValue()))
                                    .forEach(entry -> map1.computeIfAbsent(entry.getKey(), k -> new Long2ObjectArrayMap<>()).putAll(entry.getValue()));
                            return map1;
                        }
                )
        );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy