Power QueryのFuzzyJoinのしきい値を逆算しようとして駄目だった

## やりたかったこと

文字列同士の類似性をサクッと算出したかった。Power Queryでは、FuzzyJoinができるのだから、テキストの類似度を算出する関数もあるかと思いきや、どうやらないようです。

## 試したこと

かなり力技くさいのですが、2つの文字列をそれぞれテーブルにして、しきい値を変えながらFuzzyJoinを試していき、結果を取る関数を作ってみました。

```matlab:TextSimilarity
(s as text, t as text, step as number, optional joinOptions as nullable record) as number =>
let
    // 各文字列ごとに1行1列のみのテーブルを生成
    table_s = #table(type table [s = text], {{s}}),
    table_t = #table(type table [t = text], {{t}}),

    // 指定した閾値でFuzzyJoinできたかどうかを返す
    isMatch = (threshold as number) as logical =>
        not Table.IsEmpty(
            Table.FuzzyJoin(
                table_s, {"s"},
                table_t, {"t"},
                JoinKind.Inner,
                [Threshold = threshold] & (if joinOptions = null then [] else joinOptions)
            )
        ),

    // 試行する閾値をリストアップ
    li = List.Generate(
        () => 0,
        each _ < 100,
        each _ + step,
        each _ / 100
    ) & {1},

    // 二分探索してマッチする最大の閾値を特定
    fx = (left as number, right as number) =>
    let
        mid = Number.RoundDown((left + right) / 2),
        result = [left = left, right = right, mid = mid, match = isMatch(li{mid})]
    in
        result,
    results = List.Generate(
        () => fx(1, List.Count(li)),
        each [left] < [right],
        each if [match] then
            fx([mid] + 1, [right])
        else
            fx([left], [mid])
    ),
    matchedResults = List.Select(results, each [match]),
    values = List.Transform(matchedResults, each [mid]),
    ans = li{List.Max(values, 0)}
in
    ans

```

## 結果

単品では動く
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239258/f93678b4-fa3c-9d5d-a465-69de4587a6a5.png)

のですが、テーブルから```列の追加```→```カスタム関数の呼び出し```だとエラーが出て駄目でした。

<details><summary>エラー詳細</summary><div>

```
予期しないエラー: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。
詳細:
    Microsoft.Mashup.Evaluator.Interface.ErrorException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> Microsoft.Mashup.Evaluator.Interface.ErrorException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> Microsoft.Mashup.Evaluator.Interface.ErrorException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> Microsoft.Mashup.Evaluator.Interface.ErrorException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> Microsoft.Mashup.Evaluator.Interface.ErrorException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> System.InvalidOperationException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。 ---> System.InvalidOperationException: オブジェクトの現在の状態に問題があるため、操作は有効ではありません。
   場所 Microsoft.Mashup.Engine1.Language.Compiler.ToFunction(IFunctionExpression expression)
   場所 Microsoft.Mashup.Engine1.Runtime.CollapseNestedFunctionsVisitor.VisitFunction(IFunctionExpression node)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitInvocation(IInvocationExpression invocation)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.LogicalAstVisitor2`1.VisitFunction(IFunctionExpression function, IList`1 bindings)
   場所 Microsoft.Mashup.Engine1.Runtime.CollapseNestedFunctionsVisitor.VisitFunction(IFunctionExpression node)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitListElements(IExpression[] list)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitInvocation(IInvocationExpression invocation)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.LogicalAstVisitor2`1.VisitInitializer(VariableInitializer member)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitListElements(VariableInitializer[] list)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitListElements(IList`1 list)
   場所 Microsoft.Mashup.Engine.Ast.LogicalAstVisitor2`1.VisitRecord(IRecordExpression record, TBinding binding, IList`1 bindings)
   場所 Microsoft.Mashup.Engine1.Runtime.CollapseNestedFunctionsVisitor.VisitRecord(IRecordExpression node)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitFieldAccess(IFieldAccessExpression fieldAccess)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.LogicalAstVisitor2`1.VisitFunction(IFunctionExpression function, IList`1 bindings)
   場所 Microsoft.Mashup.Engine1.Runtime.CollapseNestedFunctionsVisitor.VisitFunction(IFunctionExpression node)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitInvocation(IInvocationExpression invocation)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitListElements(IExpression[] list)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitInvocation(IInvocationExpression invocation)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine.Ast.LogicalAstVisitor2`1.VisitFunction(IFunctionExpression function, IList`1 bindings)
   場所 Microsoft.Mashup.Engine1.Runtime.CollapseNestedFunctionsVisitor.VisitFunction(IFunctionExpression node)
   場所 Microsoft.Mashup.Engine.Ast.AstVisitor2.VisitExpression(IExpression expression)
   場所 Microsoft.Mashup.Engine1.Language.Query.NormalizationVisitor.Normalize(IExpression node, TypeValue[] parameterTypes, Boolean normalizeInvocation)
   場所 Microsoft.Mashup.Engine1.Language.Query.QueryExpressionBuilder.TryToQueryExpression(TypeValue type, IFunctionExpression functionExpression, QueryExpression& queryExpression)
   場所 Microsoft.Mashup.Engine1.Language.Query.AddColumnsQuery.CreateQueryExpressions(FunctionValue columnGeneratorFunction, RecordTypeValue rowType)
   場所 Microsoft.Mashup.Engine1.Language.Query.ProjectColumnsQuery.TryAddColumns(ColumnsConstructor columnGenerator, Query& query, ColumnSelection& newColumnProjection)
   場所 Microsoft.Mashup.Engine1.Language.Query.ProjectColumnsQuery.AddColumns(ColumnsConstructor columnGenerator)
   場所 Microsoft.Mashup.Engine1.Language.Query.QueryTableValue.AddColumns(ColumnsConstructor columnGenerator)
   場所 Microsoft.Mashup.Engine1.Runtime.RelatedTablesTableValue.AddColumns(ColumnsConstructor columnsConstructor)
   場所 Microsoft.Mashup.Engine1.Runtime.TableValue.AddColumns(ListValue columnNames, FunctionValue columnGenerator, Value columnTypes)
   場所 Microsoft.Mashup.Engine1.Runtime.NativeFunctionValue4`5.Invoke(Value arg0, Value arg1, Value arg2, Value arg3)
   場所 Microsoft.Mashup.Engine1.Runtime.FunctionValue.Invoke(Value[] args)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue1.Invoke(Value arg0)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RuntimeFunctionValueN.Invoke(Value[] args)
   場所 Microsoft.Mashup.Engine1.Language.FunctionInvocationInstruction2.Execute(MembersFrameN& frame)
   場所 Microsoft.Mashup.Engine1.Language.RuntimeFunctionValueN.Invoke(Value[] args)
   場所 Microsoft.Mashup.Engine1.Language.DebugInstruction.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.FunctionInvocationInstruction2.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.DebugInstruction.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.InstructionInvocationInstruction2.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.DebugInstruction.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue1.Invoke(Value arg0)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue1.Invoke(Value arg0)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Runtime.Library.Linker.BindFunctionValue.TypedInvoke(RecordValue environment, Value section, TextValue name)
   場所 Microsoft.Mashup.Engine1.Runtime.NativeFunctionValue3`4.Invoke(Value arg0, Value arg1, Value arg2)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue0.Invoke()
   場所 Microsoft.Mashup.Engine1.Language.ListInstruction.RuntimeListValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.ListInstruction.RuntimeListValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue1.Invoke(Value arg0)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.FunctionInvocationInstruction2.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.Instruction.ExecuteCondition(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.DebugInstruction.ExecuteCondition(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.IfInstruction.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.DebugInstruction.Execute(MembersFrame1& frame)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue1.Invoke(Value arg0)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.Force(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.RecordInstruction.RuntimeRecordValue.get_Item(Int32 index)
   場所 Microsoft.Mashup.Engine1.Language.MembersFunctionValue0.Invoke()
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.BeginGetResult(DocumentEvaluationParameters parameters, Action`1 callback)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.BeginGetResult(DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.BeginGetResult(DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallPartition.BeginGetResult[T](Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallDocumentEvaluator.Evaluation`1.OnBufferComplete(Exception exception)
   場所 Microsoft.Mashup.Evaluator.Firewall.BeginBufferPartitions(Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallDocumentEvaluator.BeginGetResultInternal[T](DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.Interface.IDocumentEvaluatorExtensions.GetResult[T](IDocumentEvaluator`1 evaluator, DocumentEvaluationParameters parameters)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetResult[T](IMessageChannel channel, BeginGetResultMessage message, Action`1 action)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetPreviewValueSource(IMessageChannel channel, BeginGetPreviewValueSourceMessage message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.OnMessageWithUnknownChannel(IMessageChannel baseChannel, MessageWithUnknownChannel messageWithUnknownChannel)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.Run()
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Run(Object args)
   場所 Microsoft.Mashup.Evaluator.SafeThread2.<>c__DisplayClass9_0.<CreateAction>b__0(Object o)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.SafeRun(String[] args)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Main(String[] args)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.<>c__DisplayClass3_0.<BeginGetResult>b__0(EvaluationResult2`1 result)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.<>c__DisplayClass3_0.<BeginGetResult>b__0(EvaluationResult2`1 result)
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.BeginGetResult(DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.SimpleDocumentEvaluator.BeginGetResult(DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallPartition.BeginGetResult[T](Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallDocumentEvaluator.Evaluation`1.OnBufferComplete(Exception exception)
   場所 Microsoft.Mashup.Evaluator.Firewall.BeginBufferPartitions(Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.FirewallDocumentEvaluator.BeginGetResultInternal[T](DocumentEvaluationParameters parameters, Action`1 callback)
   場所 Microsoft.Mashup.Evaluator.Interface.IDocumentEvaluatorExtensions.GetResult[T](IDocumentEvaluator`1 evaluator, DocumentEvaluationParameters parameters)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetResult[T](IMessageChannel channel, BeginGetResultMessage message, Action`1 action)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetPreviewValueSource(IMessageChannel channel, BeginGetPreviewValueSourceMessage message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.OnMessageWithUnknownChannel(IMessageChannel baseChannel, MessageWithUnknownChannel messageWithUnknownChannel)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.Run()
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Run(Object args)
   場所 Microsoft.Mashup.Evaluator.SafeThread2.<>c__DisplayClass9_0.<CreateAction>b__0(Object o)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.SafeRun(String[] args)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Main(String[] args)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.<>c__DisplayClass9_1.<OnBeginGetPreviewValueSource>b__1()
   場所 Microsoft.Mashup.Evaluator.RemotePreviewValueSource.<>c__DisplayClass0_0.<RunStub>b__0()
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.ReportExceptions(IHostTrace trace, IEngineHost engineHost, IMessageChannel channel, Action action)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.<>c__DisplayClass11_0.<TryReportException>b__1()
   場所 Microsoft.Mashup.Common.SafeExceptions.IgnoreSafeExceptions(IEngineHost host, IHostTrace trace, Action action)
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.TryReportException(IHostTrace trace, IEngineHost engineHost, IMessageChannel channel, Exception exception)
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.ReportExceptions(IHostTrace trace, IEngineHost engineHost, IMessageChannel channel, Action action)
   場所 Microsoft.Mashup.Evaluator.RemotePreviewValueSource.RunStub(IEngineHost engineHost, IMessageChannel channel, Func`1 getPreviewValueSource)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.<>c__DisplayClass12_1`1.<OnBeginGetResult>b__0()
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.ReportExceptions(IHostTrace trace, IEngineHost engineHost, IMessageChannel channel, Action action)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetResult[T](IMessageChannel channel, BeginGetResultMessage message, Action`1 action)
   場所 Microsoft.Mashup.Evaluator.RemoteDocumentEvaluator.Service.OnBeginGetPreviewValueSource(IMessageChannel channel, BeginGetPreviewValueSourceMessage message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.OnMessageWithUnknownChannel(IMessageChannel baseChannel, MessageWithUnknownChannel messageWithUnknownChannel)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.Run()
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Run(Object args)
   場所 Microsoft.Mashup.Evaluator.SafeThread2.<>c__DisplayClass9_0.<CreateAction>b__0(Object o)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.SafeRun(String[] args)
   場所 Microsoft.Mashup.Container.EvaluationContainerMain.Main(String[] args)
   --- 内部例外スタック トレースの終わり ---
   場所 Microsoft.Mashup.Evaluator.EvaluationHost.OnException(IEngineHost engineHost, IMessageChannel channel, ExceptionMessage message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.ChannelMessenger.ChannelMessageHandlers.TryDispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.MessageHandlers.Dispatch(IMessageChannel channel, Message message)
   場所 Microsoft.Mashup.Evaluator.Interface.IMessageChannelExtensions.WaitFor[T](IMessageChannel channel)
   場所 Microsoft.Mashup.Evaluator.RemotePreviewValueSource.PreviewValueSource.WaitFor(Func`1 condition, Boolean disposing)
   場所 Microsoft.Mashup.Evaluator.RemotePreviewValueSource.PreviewValueSource.get_TableSource()
   場所 Microsoft.Mashup.Evaluator.Interface.TracingPreviewValueSource.get_TableSource()
   場所 Microsoft.Mashup.Host.Document.Analysis.PackageDocumentAnalysisInfo.PackagePartitionAnalysisInfo.SetPreviewValue(EvaluationResult2`1 result, Func`1 getStaleSince, Func`1 getSampled)
```
</div>
</details>