/** * * Copyright (c) 2009-2014 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * 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, 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 * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.nlp; import com.freedomotic.exceptions.NoResultsException; import com.freedomotic.reactions.Command; import com.freedomotic.reactions.CommandRepository; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.inject.Inject; /** * Computes Commands similarity ranking usin Damerau-Levenstrin string distance * algorithm * * @see Command * @author Enrico Nicoletti */ public class NlpCommandStringDistanceImpl implements NlpCommand { private List<Rank<Command>> ranking; private final CommandRepository commandsRepository; @Inject public NlpCommandStringDistanceImpl(CommandRepository commandsRepository) { this.commandsRepository = commandsRepository; } /** * {@inheritDoc} May return also elements with similarity equals to zero. * * @param inputText * @return */ @Override public List<Rank<Command>> computeSimilarity(String inputText, int maxResults) throws NoResultsException { ranking = new ArrayList<>(); buildRanking(inputText); Collections.sort(ranking, new DescendingRankComparator()); // for (Rank<Command> r : ranking) { // if (r.getSimilarity() > 0) { // System.out.println(r.getElement().getName() + " points " + r.getSimilarity()); // } // } if (ranking.isEmpty()) { return Collections.unmodifiableList(ranking); } else { return Collections.unmodifiableList(ranking.subList(0, Math.min(maxResults - 1, ranking.size()))); } } /** * Tokenize the string and compute string distance using Damerau-Levensthein * algorithm. May return also elements with similarity equals to zero. * * @param input */ private void buildRanking(String input) { if (input == null || input.isEmpty()) { return; } DamerauLevenshtein algorithm = new DamerauLevenshtein(); for (Command command : commandsRepository.findAll()) { int similarity = 0; // Compare every word of the input to any word in the command name for (String inputWord : Arrays.asList(input.split(" "))) { // Use the command name not the command tags for this for (String commandWord : Arrays.asList(command.getName().split(" "))) { algorithm.setWordsToCompare(inputWord.trim().toLowerCase(), commandWord.trim().toLowerCase()); int distance = algorithm.getSimilarity(); //convert word distance into a percent value double distancePercent = ((double) (distance * 100)) / ((double) inputWord.length()); if (distancePercent == 0) { similarity += 30; //3 points for any idenitical word } else { if (distancePercent <= 30) { //30% of error, not too much, it can be a typo, give it some points similarity += 15; } } } } ranking.add(new Rank(similarity, command)); } } }