Current section
Files
Jump to
Current section
Files
lib/match_jaro.txt
defmodule Superls.MatchJaro do
use Superls
@moduledoc false
# group files by similar tags
@jaro_threshold Application.compile_env!(:superls, :jaro_threshold)
def pretty_print_result(result) do
for {d, similar_files} <- result do
IO.write(
IO.ANSI.light_magenta() <>
IO.ANSI.reverse() <>
"distance: #{d}" <>
IO.ANSI.reverse_off() <>
"________________________________________________________________" <>
IO.ANSI.reset()
)
for {{file1, vol1}, {file2, vol2}} <- similar_files do
# " - " <>
# " - " <>
("\n" <>
IO.ANSI.bright() <>
Path.basename(file1.name) <>
IO.ANSI.reset() <>
"\t" <>
Superls.pp_sz(file1.size) <>
"\t" <>
vol1 <>
"/" <>
Path.dirname(file1.name) <>
IO.ANSI.reset() <>
"\n" <>
IO.ANSI.bright() <>
Path.basename(file2.name) <>
IO.ANSI.reset() <>
"\t" <>
Superls.pp_sz(file2.size) <>
"\t" <>
vol2 <> "/" <> Path.dirname(file2.name) <> IO.ANSI.reset())
|> IO.puts()
end
end
end
def best_jaro(files) do
len = length(files)
files =
files
|> build_f_mapset([])
|> Superls.build_indexed_list(len)
files
|> Flow.from_enumerable()
|> Flow.flat_map(fn {{file_vol, set, len}, start_compare} ->
jaro_per_file_mapset(Enum.slice(files, start_compare..len), file_vol, set, len, [])
end)
|> Flow.partition(key: {:elem, 0})
|> Flow.reduce(fn -> %{} end, &best_jaro_reduce/2)
|> Enum.into(%{})
end
defp best_jaro_reduce({d, similar_files_tuple}, acc) do
case acc do
%{^d => list} ->
if :lists.member(similar_files_tuple, list) do
acc
else
%{acc | d => [similar_files_tuple | list]}
end
%{} ->
Map.put(acc, d, [similar_files_tuple])
other ->
:erlang.error({:badmap, other}, [acc, d, [similar_files_tuple]])
end
end
defp build_f_mapset([], result), do: result
defp build_f_mapset([{file_volume, tags} | rest], acc) do
set = Enum.join(tags, "-")
build_f_mapset(rest, [{file_volume, set, byte_size(set)} | acc])
end
defp jaro_per_file_mapset([], _file_vol, _set, _len, acc),
do: acc
defp jaro_per_file_mapset([{{file2_vol, set2, len2}, _} | rest], file_vol, set1, len1, acc) do
d = try do
if len1 < len2 do
:jaro.similarity(set1, binary_part(set2, 0, len1))
else
:jaro.similarity(binary_part(set1, 0, len2), set2)
end
rescue
_err ->
# IO.puts "#{set2} #{inspect( err)}"
0
end
if d >= @jaro_threshold do
jaro_per_file_mapset(rest, file_vol, set1, len1, [
{d, List.to_tuple(Enum.sort([file_vol, file2_vol]))} | acc
])
else
jaro_per_file_mapset(rest, file_vol, set1, len1, acc)
end
end
# tvnum-streaming-rfc3640-rtp-payload-format-for-transport-of-mpeg-4-elementary-streams-pdf
# tutorials-opengl-tutoriel-lausanne-icwww-epfl-ch-sam-prjinfosv-tutorial-wxwidget-img-wxwi
# rfc3640 (RTP Payload Format for Transport of MPEG-4 Elementary Streams).pdf
# Superls.MatchJaro.test ["elvis","and","anabelle","2007","webrip","rarbg"],["elvis","and","anabelle","2007","amzn","web","dl","ddp2","0","h","264","tepes","slow26"]
# Superls.MatchJaro.test ["the", "six", "million", "dollar", "man", "s02e08", "dvdrip", "naneboy"], ["elvis", "and", "anabelle", "2007"]
def test(tag1s, tag2s) do
set1 = MapSet.new(tag1s)
set2 = MapSet.new(tag2s)
seti = MapSet.intersection(set1, set2)
setu = MapSet.union(set1, set2)
{MapSet.size(seti) / MapSet.size(setu), Levenshtein.distance(tag1s, tag2s),
Jaro.jaro_distance(tag1s, tag2s), :jaro.similarity(tag1s, tag2s)}
end
def test1(tag1s, tag2s) do
str1 = Enum.join(tag1s, "-")
str2 = Enum.join(tag2s, "-")
len1 = byte_size(str1)
len2 = byte_size(str2)
d =
if len1 < len2 do
:jaro.similarity(str1, binary_part(str2, 0, len1))
else
:jaro.similarity(binary_part(str1, 0, len2), str2)
end
{d, str1, str2}
end
end