SQL Serverは最短経路検索アルゴリズムを実装しています

SQL Serverは最短経路検索アルゴリズムを実装しています

これは去年の質問です。今日メールを整理していたら偶然見つけました。とても興味深いと思ったので書き留めておきました。

図1.

分析

RelationGraph テーブル内の Node フィールドと RelatedNode フィールド間の関係をよりわかりやすく説明するために、図 2 に示すようにグラフを使用して説明します。

図2.

図 2 では、ノードがどのように直接接続されているかが明確にわかります。また、ノード「p」からノード「j」へのいくつかの可能なパスも明確に確認できます。

上記から、2 番目の可能なパスは、最も少ない数のノードを通過することがわかります。

最初の問題を解決するために、私は2つの方法を参考にしました。

最初の方法は、

単一ソースの最短経路アルゴリズムであるダイクストラ アルゴリズムを参照してください。このアルゴリズムの主な特徴は、開始点を中心にして、終了点に到達するまで層ごとに外側に拡張することです。

図3.

2番目の方法は、

最初の方法の改良は、図 4 に示すように、ノード「p」とノード「j」を中心として 2 つの円の外接点まで外側に拡張するマルチソース ポイント法を使用することです。

図4.

成し遂げる

次に、SQL Server での実装方法について説明します。もちろん、ここで私が使用するのは、前述の 2 番目の方法で、「P」と「J」を起点として、中心から層ごとに外側に拡張します。

以下は、RelactionGraph テーブルにデータを作成して挿入するためのスクリプトです。

  1. TestDBを使用する
  2. 行く
  3. object_id( 'RelactionGraph' ) がnullでない場合は、テーブル RelactionGraph を削除します。
  4. テーブル RelactionGraph を作成します (ID int identity、Item nvarchar(50)、RelactionItemnvarchar(20)、制約 PK_RelactionGraph 主キー (ID))
  5. 行く
  6. RelactionGraph(Ite​​m)include(RelactionItem) に非クラスター化インデックス IX_RelactionGraph_Item を作成します。
  7. RelactionGraph(RelactionItem)include(Item) に非クラスター化インデックス IX_RelactionGraph_RelactionItem を作成します。
  8. 行く
  9. RelactionGraph (Item, RelactionItem) の値を挿入する
  10. ( 'a' 'b' )、( 'a' 'c' )、( 'a' 'd' )、( 'a' 'e' )、
  11. ( 'b' 'f' )、( 'b' 'g' )、( 'b' 'h' )、
  12. ( 'c' 'i' )、( 'c' 'j' )、
  13. ( 'f' 'k' )、( 'f' 'l' )、
  14. ( 'k' 'o' )、( 'k' 'p' )、
  15. ( 'お' 'い' )、( 'お' 'l' )
  16. 行く

ストアドプロシージャup_GetPathを書く

  1. TestDBを使用する
  2. 行く
  3. dbo.up_GetPathを実行します
  4. @Node = 'p'
  5. @関連ノード = 'j'  
  6. 行く

上記のストアド プロシージャは、主に 2 つの部分に分かれています。最初の部分は検索を実装する方法であり、2 番目の部分は戻り結果を構築する方法です。パート 1 のコードは、前の方法 2 に従って、@Node ノードと @RelatedNode ノードを介して外側のレイヤーを検索します。各検索で返されたノードは、一時テーブル #1 と #2 に保存されます。次に、一時テーブル #1 と #2 に接点があるかどうかが判断されます。接点がある場合は、最短パス (通過するノード数が最も少ない) が見つかったことを意味します。接点がない場合は、最大検索深度 (@MaxLevel smallint=100) に達するか、接点が見つかるまで、検索はループで続行されます。 100 層後に交差点が見つからない場合、検索は中止されます。ここで、検索可能な最大深度 @MaxLevel は、データ量が検索パフォーマンスに反比例するため、大量のデータによって発生する可能性のあるパフォーマンスの低下を制御するために使用されます。コードには、主に Node と RelatedNode を基準とした前方検索と後方検索についても記載されています。これらは相互参照オブジェクトであり、外向き検索に使用されます。

ストアド プロシージャの実行は次のとおりです。

必要に応じて@Nodeと@RelatedNodeに異なる値を割り当てることができます。

  1. TestDBを使用する
  2. 行く
  3. - 手順:
  4. object_id( 'up_GetPath' ) がnullでない場合 
  5. ドロッププロシージャ up_GetPath
  6. 行く
  7. プロシージャ up_GetPath を作成する
  8. @Node nvarchar(50)、
  9. @関連ノード nvarchar(50)
  10. として
  11. ノーカウントをオンに設定
  12. 宣言する
  13. @level smallint =1, --現在の検索の深さ
  14. @MaxLevel smallint=100, --***検索可能な深さ
  15. @Node_WhileFlag ビット=1、 --@Nodeを中心に検索する場合、ループで検索するかどうかを決定するフラグとして使用されます
  16. @RelatedNode_WhileFlag ビット=1 --@RelatedNodeを中心に検索する場合、ループで検索するかどうかを決定するフラグとして使用されます
  17. --直接関係のある2つのノードが見つかった場合は、直接戻ります
  18. 存在する場合(RelationGraph から 1 つを選択、(Node=@Node かつ RelatedNode=@RelatedNode)
  19. または(Node=@RelatedNode And RelatedNode=@Node) )または @Node=@RelatedNode
  20. 始める
  21. convert(nvarchar(2000),@Node + ' --> ' + @RelatedNode) AsRelationGraphPath,convert(smallint,0) As StopCount を選択します。
  22. 戻る 
  23. 終わり
  24. --
  25. if object_id( 'tempdb..#1' ) Is not null Drop Table #1 -- 一時テーブル#1は@Nodeを中心に外側に広がる各ノードのデータを格納する
  26. if object_id( 'tempdb..#2' ) Is not null Drop Table #2 -- 一時テーブル#2には、@RelatedNodeを中心に外側に広がる各ノードのデータが格納されます。
  27. テーブル#1を作成(
  28. ノード nvarchar(50),--相対ソースポイント
  29. 関連ノード nvarchar(50), --相対ターゲット
  30. レベル smallint --depth
  31. テーブル #2 を作成します (Node nvarchar(50),RelatedNode nvarchar(50),Level smallint)
  32. #1 ( ノード、関連ノード、レベル ) に挿入します
  33. select Node, RelatedNode, @level from RelationGraph a where a.Node =@Node union --Forward: @Node をソースクエリとして使用します
  34. select RelatedNode, Node, @level from RelationGraph a where a.RelatedNode = @Node --Reverse: @Node をターゲットとしてクエリを実行します
  35. @Node_WhileFlag を sign(@@rowcount) に設定します
  36. #2 ( ノード、関連ノード、レベル ) に挿入します
  37. select Node, RelatedNode, @level from RelationGraph a where a.Node =@RelatedNode union --Forward: @RelatedNode をソースクエリとして使用します
  38. select RelatedNode, Node, @level from RelationGraph a where a.RelatedNode = @RelatedNode -- 逆: @RelatedNode をターゲットとしてクエリを実行します
  39. @RelatedNode_WhileFlag=sign(@@rowcount)を設定します
  40. --RelationGraphテーブルに@Nodeまたは@RelatedNodeデータが見つからない場合は、後続のWhileプロセスを直接スキップします。
  41. 存在しない場合(#1 から 1 つを選択) または存在しない場合(#2 から 1 つを選択)
  42. 始める
  43. While_Outに移動
  44. 終わり
  45. while not exists(select 1 from #1 a inner join #2 b on b.RelatedNode=a.RelatedNode) --カットポイントが発生するかどうかを判断します
  46. かつ (@Node_WhileFlag|@RelatedNode_WhileFlag)>0 -- 検索が可能かどうかを判定する
  47. そして@level<@MaxLevel --深さを制御する
  48. 始める
  49. @Node_WhileFlag >0 の場合
  50. 始める
  51. #1 ( ノード、関連ノード、レベル ) に挿入します
  52. - フォワード
  53. a.Node、a.RelatedNode、@level+1 を選択
  54. RelationGraphから
  55. where exists(#1 から 1 を選択 where RelatedNode=a.Node And Level=@level) And
  56. 存在しません(Node=a.Node の場合、#1 から 1 つを選択)
  57. 連合
  58. - 逆行する
  59. a.RelatedNode、a.Node、@level+1 を選択
  60. RelationGraphから
  61. where exists(#1 から 1 を選択 where RelatedNode=a.RelatedNode AndLevel=@level) And
  62. 存在しません(Node=a.RelatedNode の場合、#1 から 1 つを選択)
  63. @Node_WhileFlag を sign(@@rowcount) に設定します
  64. 終わり
  65. @RelatedNode_WhileFlag > 0 の場合
  66. 始める
  67. #2 ( ノード、関連ノード、レベル ) に挿入します
  68. - フォワード
  69. a.Node、a.RelatedNode、@level+1 を選択
  70. RelationGraphから
  71. where exists(#2 から 1 を選択 where RelatedNode=a.Node And Level=@level) And
  72. 存在しません(Node=a.Node の場合、#2 から 1 つを選択)
  73. 連合
  74. - 逆行する
  75. a.RelatedNode、a.Node、@level+1 を選択
  76. RelationGraphから
  77. where exists(#2 から 1 を選択 where RelatedNode=a.RelatedNode AndLevel=@level) And
  78. 存在しません (Node=a.RelatedNode の場合、#2 から 1 つを選択)
  79. @RelatedNode_WhileFlag=sign(@@rowcount)を設定します
  80. 終わり
  81. @level+=1 を選択
  82. 終わり
  83. アウト中:
  84. --以下は、構築によって返される結果パスです
  85. object_id( 'tempdb..#Path1' ) がnullでない場合は、テーブル #Path1 を削除します。
  86. object_id( 'tempdb..#Path2' ) がnullでない場合は、テーブル #Path2 を削除します。
  87. ;cte_path1 の場合
  88. a.Node、a.RelatedNode、Level を選択し、convert(nvarchar(2000)、a.Node+ ' -> ' +a.RelatedNode) AsRelationGraphPath、Convert(smallint,1) As PathLevel
  89. #1 から、存在する a があります (RelatedNode=a.RelatedNode である #2 から 1 つを選択)
  90. すべて結合
  91. b.Node、a.RelatedNode、b.Level を選択し、convert(nvarchar(2000)、b.Node+ ' -> ' +a.RelationGraphPath) を RelationGraphPath として変換し、Convert(smallint、a.PathLevel+1) を実行します。
  92. PathLevelとして
  93. cte_path1から
  94. 内部結合 #1 b を b.RelatedNode=a.Node に結合
  95. b.レベル=a.レベル-1
  96. cte_path1 から #Path1 に * を選択します
  97. ;cte_path2 の場合
  98. a.Node、a.RelatedNode、Level を選択し、convert(nvarchar(2000)、a.Node) AsRelationGraphPath、Convert(smallint,1) As PathLevel
  99. #2 から、存在する a があります (RelatedNode=a.RelatedNode である #1 から 1 つを選択)
  100. すべて結合
  101. b.Node、a.RelatedNode、b.Level、convert(nvarchar(2000)、a.RelationGraphPath+ ' -> ' +b.Node) を RelationGraphPath として選択し、Convert(smallint、a.PathLevel+1) を実行します。
  102. cte_path2から
  103. 内部結合 #2 b を b.RelatedNode=a.Node に結合
  104. b.レベル=a.レベル-1
  105. cte_path2 から #Path2 に * を選択します
  106. ;cte_result と
  107. a.RelationGraphPath+ ' -> ' +b.RelationGraphPath を選択 AsRelationGraphPath,a.PathLevel+b.PathLevel -1
  108. StopCount として、rank() over(order bya.PathLevel+b.PathLevel) として Result_row
  109. #Path1から
  110. #Path2 b を b.RelatedNode=a.RelatedNode に内部結合します。
  111. b.レベル=1
  112. ここで、a.Level=1
  113. Result_row=1 の cte_result から、異なる RelationGraphPath、StopCount を選択します。
  114. 行く

拡張機能

前の例は、都市のバス路線に拡張できます。2 つの停留所がある場合、これらの 2 つの停留所を通過する停留所が最も少ないバス路線を検索します。また、コミュニティ内の人間関係の検索にも拡張できます。たとえば、ある人が別の人と知り合いになりたい場合、そこにたどり着くまでに何人の人を直接通り抜ける必要がありますか。人と人とのつながりは、友人や親戚など直接的なつながりだけでなく、人と物とのつながりからも見つけられます。例えば、複数の作家が本を出版した場合、ある本の著者名簿から、共同で本を出版したというつながりがわかります。これは、2人が知り合った経緯を探す際の参考にもなります。この問題は非常に大きく複雑かもしれませんが、次のように拡張できます。

まとめ

ここでは、2 つのノード間のすべてのパスのうち、ノード数が最も少ないパスを見つけるだけです。実際のアプリケーションでは、これよりも複雑な状況に遭遇する可能性があります。他の環境やシナリオでは、長さ、時間、複数のノード、複数のスコープなどの情報が含まれる場合があります。いずれにしても、それを実装するには、一般的にいくつかの原則とアルゴリズムを参照する必要があります。

オリジナルリンク: http://www.cnblogs.com/wghao/archive/2013/04/23/3036965.html

【編集者のおすすめ】

  1. SQL Server シンプル モードで誤って削除されたヒープ テーブル レコードを回復する
  2. Microsoft SQL Server データ エンジンと分析サービス
  3. 製品推奨を実現するための SQL Server データ マイニング ルール 1
  4. SQL Server の高度なコンテンツ: サブクエリとテーブル リンク
  5. SQL Server 2008 のデータ圧縮

<<:  文字列マッチングのためのボイヤー・ムーアアルゴリズム

>>:  ビッグデータと人工知能のために生まれた新しい職業:アルゴリズム専門家

ブログ    

推薦する

教師なし学習のためのアンサンブル法: 類似度行列のクラスタリング

機械学習において、アンサンブルという用語は、複数のモデルを並行して組み合わせることを指します。その考...

...

中国がテンセントやアリババなどのプラットフォーム構築に力を入れている中、日本は何をしているのでしょうか?

中国ではブロックチェーン、ニューリテール、シェアサイクルが急成長しているが、技術大国である日本は明ら...

人工知能がクラウド業界を変える5つの方法

2023年には人工知能が最も重要な技術トレンドになることは間違いありません。 AI テクノロジーは新...

人工知能: キャリア開発のための3つの戦略

ビジネスに AI を導入するには、テクノロジーとスキルだけでは不十分です。いくつかの戦略を導入するこ...

人工知能はスマートシティの夢の実現にどのように役立つか

2008 年の金融危機後、都市計画とサービス提供に対する新しいアプローチが世界中で定着し始めました。...

...

人工知能は私たちに何をもたらしてくれるのでしょうか?人工知能は非常に強力です

人工知能は皆さんにとって馴染み深いものかもしれませんが、では人工知能は一体何ができるのでしょうか?本...

AIが本当に成功する方法

[[412385]]人工知能は現在、特に自動運転車でより広く深く活用されています。人工知能を使用して...

すごい...正義のために親族を殺す? Google AI、米国の月面着陸写真は偽物だと判定

1969年、アポロ11号が月面着陸に成功し、アームストロング船長は、今日でも数え切れないほどの人々が...

...

暗号化アルゴリズムの鍵交換は少し安全ではない

今日は対称暗号化アルゴリズムの重要な問題についてお話ししましょう。暗号化の基本的な概念に精通していな...

...

企業で文明的な AI を推進するための 6 つのヒント

「文明化された AI」への期待が高まるにつれ、コンサルタントは公平で偏見のないアルゴリズムを作成する...

人工知能が伝統文化に新たな命を吹き込む。パンダ型ロボット「Youyou」が国境を越えて「新年クロストーク会議」に参加

「パンダはトークができる、パンダはジョークを言うことができる、パンダは書道を書ける、そしてパンダはチ...