PDA

View Full Version : حرفه ای: پیدا کردن والد های یک فرزند



رامین مرادی
پنج شنبه 30 شهریور 1402, 14:50 عصر
سلام وقت بخیر دوستان یک سری متن هست که به صورت رابطه فرزندی و والدی به صورت (آی دی - والد-متن) ذخیره شده.



حالا من میام یه سری متن جستجو میکنم مثلا 10 ردیف خروجی میده که فلان آی دی ها متن های مورد جستجوی شما رو داره.

حالا خواسته من از این نتایج این هست که هر ردیفی که تو جستجو میاره سلسه مراتبی که به این فرزند میاره هم نشون بدم.
ممنون میشم راهکاری برای این مورد برام بفرمایید.

پرستو پارسایی
جمعه 31 شهریور 1402, 09:21 صبح
برای نمایش سلسله مراتبی فرزندان هر ردیف که به متن جستجوی شما مربوط می‌شود، می‌توانید از یک ساختار داده مانند درخت استفاده کنید. در این ساختار، هر گره (Node) شامل اطلاعات ردیف (آی دی و متن) و فرزندان آن می‌باشد. مثلا :

public class Node{
public int Id { get; set; }
public string Text { get; set; }
public List<Node> Children { get; set; }


public Node(int id, string text)
{
Id = id;
Text = text;
Children = new List<Node>();
}
}



سپس، با استفاده از این کلاس، درختی از گره‌ها بسازید و سپس جستجوی موردی را انجام دهید. در هر مرحله، اگر یک گره با متن مورد جستجو پیدا شود، این گره را به همراه زیردرخت آن را نمایش دهید. بعنوان مثال :

// ساخت درخت از گره‌ها
Node root = new Node(1, "Root"); // گره اصلی


Node child1 = new Node(2, "Child 1"); // فرزندان گره اصلی
Node child2 = new Node(3, "Child 2");
Node child3 = new Node(4, "Child 3");


Node grandchild1 = new Node(5, "Grandchild 1"); // فرزندان گره Child 1
Node grandchild2 = new Node(6, "Grandchild 2");


child1.Children.Add(grandchild1);
child1.Children.Add(grandchild2);


root.Children.Add(child1);
root.Children.Add(child2);
root.Children.Add(child3);


// جستجو و نمایش سلسله مراتبی فرزندان
string searchText = "متن جستجوی شما";
SearchAndDisplayHierarchy(root, searchText);


// تابع جستجو و نمایش سلسله مراتبی فرزندان
public void SearchAndDisplayHierarchy(Node node, string searchText)
{
if (node.Text.Contains(searchText))
{
DisplayHierarchy(node);
}


foreach (Node child in node.Children)
{
SearchAndDisplayHierarchy(child, searchText);
}
}


// تابع نمایش سلسله مراتبی فرزندان
public void DisplayHierarchy(Node node, string indent = "")
{
Console.WriteLine(indent + node.Text);


foreach (Node child in node.Children)
{
DisplayHierarchy(child, indent + " ");
}
}

در این کد، یک درخت ساخته شده و سپس با استفاده از تابع SearchAndDisplayHierarchy و تابع DisplayHierarchy، سلسله مراتبی فرزندان ردیف‌هایی که متن جستجوی شما را دارند نمایش داده می‌شه. اگر این نمونه با نوع سوالتان مطابقت داشت کد را با داده‌های واقعی و ساختار فرزندی خودتان سفارشی کنید.
این توضیحات درک من از نوع سوال شما هست امیدوارم کمک کنه.

رامین مرادی
شنبه 01 مهر 1402, 07:47 صبح
برای نمایش سلسله مراتبی فرزندان هر ردیف که به متن جستجوی شما مربوط می‌شود، می‌توانید از یک ساختار داده مانند درخت استفاده کنید. در این ساختار، هر گره (Node) شامل اطلاعات ردیف (آی دی و متن) و فرزندان آن می‌باشد.
در این کد، یک درخت ساخته شده و سپس با استفاده از تابع SearchAndDisplayHierarchy و تابع DisplayHierarchy، سلسله مراتبی فرزندان ردیف‌هایی که متن جستجوی شما را دارند نمایش داده می‌شه. اگر این نمونه با نوع سوالتان مطابقت داشت کد را با داده‌های واقعی و ساختار فرزندی خودتان سفارشی کنید.
این توضیحات درک من از نوع سوال شما هست امیدوارم کمک کنه.
ممنون از راهنماییتون . این دیتا ها داخل دیتابیس ذخیره شده و حجم بالایی داره. و روز به روز هم داره تعدادش بالا میره و واکشی اطلاعات و ایجاد این کلاس فکر نکنم منطقی باشه.
داده ها عین منو چند سطحی ذخیره شده (آی دی - آی دی والد- متن) ممکنه سطحی اصلا زیر مجموعه نداشته باشه و ممکنه تا ده سطح هم پیش بره. شما فکر کنید در حال حاضر 50 هزار رکورد هست که فعلا در حال رشد هست.
خودم ایده ای که دارم اینه که بعد از هر جستجو کاربر بیاد و با یک کلید دیگه روی هر ردیف ساختار پدر فرزندی که به این نود میرسه رو دوباره جستجو بزنه!.

mazoolagh
دوشنبه 03 مهر 1402, 17:51 عصر
یک راه هم اینه که حجم دیتابیس رو فدای سرعت کنین!

یک فیلد دیگه به جدول اضافه کنین به اسم path و در همون زمان insert/update مسیر رو هم بسازین و در اون ذخیره کنین.
چون مسیر parent هر node از قبل مشخصه، زمانبر هم نیست و اگر batch هم باشه سرعت کم نمیشه،
چون کافی هست parent به مسیر parent اضافه و در مسیر child ذخیره بشه.

از طرفی،
شاید نگرانی شما برای رکوردی های زیاد چندان موردی نداشته باشه.
المانهای فایل های html یا گره های xml هم ساختا مشابه دارن و parserها سریع در اونها جستجو میکنن و تازه اینها دیتابیس هم نیستن.

شاید اگر یک دیتابیس تست با چند میلیون رکورد بسازین و شرایط جستجو رو شبیه سازی کنین نگرانی رفع بشه،
و همین کد پست 2 که پیشنهاد هوش ساختگی هست، ممکنه مناسب باشه (یا با ویرایش درست بشه).
چون بیشتر اینها رو بر اساس دیتابیس learn مایکروسافت و پاسخ های پذیرفته شده جاهایی مثل stackoverflow میاره.
به هر حال پرسش شما از نوعی هست که قبلا برای خیلی ها پیش آمده و معمولا برای اینها جواب های خوبی پیدا میشه.

رامین مرادی
یک شنبه 09 مهر 1402, 13:11 عصر
یک راه هم اینه که حجم دیتابیس رو فدای سرعت کنین!

یک فیلد دیگه به جدول اضافه کنین به اسم path و در همون زمان insert/update مسیر رو هم بسازین و در اون ذخیره کنین.
چون مسیر parent هر node از قبل مشخصه، زمانبر هم نیست و اگر batch هم باشه سرعت کم نمیشه،
چون کافی هست parent به مسیر parent اضافه و در مسیر child ذخیره بشه.

از طرفی،
شاید نگرانی شما برای رکوردی های زیاد چندان موردی نداشته باشه.
المانهای فایل های html یا گره های xml هم ساختا مشابه دارن و parserها سریع در اونها جستجو میکنن و تازه اینها دیتابیس هم نیستن.

شاید اگر یک دیتابیس تست با چند میلیون رکورد بسازین و شرایط جستجو رو شبیه سازی کنین نگرانی رفع بشه،
و همین کد پست 2 که پیشنهاد هوش ساختگی هست، ممکنه مناسب باشه (یا با ویرایش درست بشه).
چون بیشتر اینها رو بر اساس دیتابیس learn مایکروسافت و پاسخ های پذیرفته شده جاهایی مثل stackoverflow میاره.
به هر حال پرسش شما از نوعی هست که قبلا برای خیلی ها پیش آمده و معمولا برای اینها جواب های خوبی پیدا میشه.


چون جدول ساخته شده فعلا امکانش نیست بیام فیلد مسیر رو اضافه کنم و مسیر هر والد رو براشون بنویسم. (تعداد زیاده:لبخند:)

داده های من مثل جدول زیر هستند
154979

الان میخوام دنبال کلمه Ali بگردم
نتایجی که بدست میارم رو میخوام این ستون رو هم داشته باشه که این ردیفی که پیدا کرده از چه مسیری به این رسیده یعنی پدر های این ردیف رو هم برام بنویسه.

mazoolagh
چهارشنبه 12 مهر 1402, 15:21 عصر
من یک دیتابیس نمونه از تقسیمات کشوری دارم
که پنج جدول اصلی داره : states - counties - divisions - cities - villages

از روی این 5 جدول، یک جدول Locations ساختم که ساختارش مشابه جدول شماست (parent-child hierarchical)

روی همین دیتا توضیح میدم روش کار رو - شما برای مسئله خودتون تغییر بدین.

154984

همینجور که میبینین در زمان ساخت این جدول مسیر IDها و Locationها هم در جدول ساخته شده (فیلدهای Path و $Path) ،
بنابراین با جستجوی یک location همزمان هر دو مسیر رو هم داریم و نیازی به کار دیگه ای نیست:
154985

mazoolagh
چهارشنبه 12 مهر 1402, 15:47 عصر
فرض میکنیم که به هر دلیلی امکان ساخت فیلدهای Path و $Path نیست.

میتونیم یک stored procedure بنویسیم که با گرفتن یک ID ، بصورت recursive تمام رکوردهای parent رو برگردونه:
USE [Iran]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[GetParents]
@ID int
AS
BEGIN
SET NOCOUNT ON;

WITH All_Parents(ID) AS
(
SELECT ParentID FROM Locations WHERE ID=@ID
UNION ALL
SELECT L.ParentID
FROM All_Parents
INNER JOIN Locations AS L
ON All_Parents.ID=L.ID
)

SELECT L.ID, L.ParentID, L.[Location]
FROM All_Parents
INNER JOIN Locations AS L
ON All_Parents.ID = L.ID
END
GO

بعنوان نمونه، در تصویر دوم پست قبلی برای ردیف 9 با ID=1029852 خواهیم داشت:
154987
EXEC GetParents @ID = 1029852

154986

mazoolagh
چهارشنبه 12 مهر 1402, 16:03 عصر
همچنین میتونیم بجای برگرداندن رکوردها، مسیرها رو برگردونیم:
USE [Iran]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[GetParentsPath]
@ID int
AS
BEGIN
SET NOCOUNT ON;

WITH All_Parents(ID) AS
(
SELECT ParentID FROM Locations WHERE ID=@ID
UNION ALL
SELECT L.ParentID
FROM All_Parents
INNER JOIN Locations AS L
ON All_Parents.ID=L.ID
)

SELECT
STRING_AGG (RESULTS.ID , '/') AS [PATH],
STRING_AGG (RESULTS.[Location] , '/') AS [PATH$]
FROM
(SELECT L.ID AS ID, L.ParentID, L.[Location]
FROM All_Parents
INNER JOIN Locations AS L
ON All_Parents.ID = L.ID) AS RESULTS

END
GO

EXEC GetParentsPath @ID = 1029852

154989

رامین مرادی
پنج شنبه 13 مهر 1402, 11:22 صبح
همچنین میتونیم بجای برگرداندن رکوردها، مسیرها رو برگردونیم:

ممنون به روش کوئری بازگشتی انجام دادم. (recursive ) دستتون درد نکنه بابت وقتی که گذاشتید