דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. ביצוע פרקטי לאינדוקס מאגר טקסט עברי

ביצוע פרקטי לאינדוקס מאגר טקסט עברי

מתוזמן נעוץ נעול הועבר תכנות
12 פוסטים 3 כותבים 540 צפיות 2 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • dovidD dovid

    תגובה: שאלה: מה הסוד מאחורי מנוע החיפוש של בר אילן? (מבחינת תיכנות)

    @pcinfogmach
    הסברתי לך שאפשר לבנות קובץ בפורמט שמאפשר גישה אקראית, כלומר כדי לקרוא פיסת מידע 5026, לא צריך לקרוא מתחילת הקובץ אלא אפשר להזיז את מיקום הקריאה מיידית למקום הרצוי.
    כשכתבתי זאת חשבתי שאתה מתעניין תיאורטית. אם אתה מחפש מעשית כזו אפשרות, הדרך הקלה ביותר זה מסד נתונים.
    מסד נתונים זה ארגון נתונים על גבי דיסק בצורה חכמה, באופן שאפשר לדלג מרשומה לרשומה במהירות ואף לבנות מאחורי הקלעים רשימות אינדוקס. האינדקס במסד נתונים לטקסט רגיל הינו רק "מתחיל ב" ואילו ל"מכיל" או "נגמר ב" מחוייבת סריקה מלאה, אבל הסריקה המלאה הזו לא איטית בכלל, בגלל המימוש המוצלח.

    יש הרבה שיוכלו להכניס אתכם לעולם המסד נתונים לכן אני לא מפרט בעניין, לתוכנה ניידת טוב להשתמש בsqlite שזה מסד נתונים נייד (הכונה שהמנוע שלו זה ספריה שרצה כחלק מהתוכנה שלכם ולא תוכנה חיצונית) פופולרי.
    לגבי הפרוייקט שלכם תוכלו לבנות רשימת מילים, ולהכניס לטבלה את הפרטים הבאים:
    המילה, מס' ספר, מס' שורה/פסקה, מיקום
    בטבלה אחרת להכניס את הנתונים עצמם לשליפה מהירה של פסקאות של ספרים, ככה:
    מס' פסקה (מספר רץ), פסקה, מס' ספר

    על הטבלה הראשונה צריך להגדיר אינדקס על העמודה של המילה, וזהו, בעת חיפשו מילים שלמות פשוט מאתרים את המילים בטבלה ומחפשים האם ישנו רצף לפי קריטריון המרחק. אם המחפש ישים תו לתחיליות וסיומות כמו ה* בבר אילן, תצטרכו לחפש מכיל שזה סריקה מאלה, אבל זה עדיין יהיה מהר מאוד בטקסטים תורניים שיש להם סוף.
    אפשר לשפר בהרבה את כל האינדוקס אבל זה נראה לי מיותר, המהירות של בר אילן קלה להשגה לדעתי גם בטכניקות כאלה שהזכרתי.
    (הם לא משתמשים כנראה בsqlite אלא הם מימשו פרוטוקול לארגון מילים לבד, אבל בהחלט הם מבוססים על רשימת מילים).

    pcinfogmachP מנותק
    pcinfogmachP מנותק
    pcinfogmach
    כתב ב נערך לאחרונה על ידי pcinfogmach
    #2

    @dovid
    תודה רבה על המענה הנפלא!

    יצרנו תוכנה בסיסית לבדוק את sqlite
    הבעיה שהאטיות שלו בבניית האינדקס פשוט לא פרקטית

    אולי אנחנו לא בנינו את הקוד נכון?
    בכל אופן מצו"ב הקוד בc# אם מישהו יכול לעזור

    using System;
    using System.Data.SQLite;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    
    namespace TestSqlite
    {
        public partial class Form1 : Form
        {
            private ProgressBar progressBar;
            private Label progressLabel;
    
            public Form1()
            {
                InitializeComponent();
                InitializeUI();
            }
    
            private void InitializeUI()
            {
                Button startIndexingButton = new Button();
                startIndexingButton.Text = "Start Indexing";
                startIndexingButton.Click += StartIndexingButton_Click;
                startIndexingButton.Dock = DockStyle.Top;
    
                progressBar = new ProgressBar();
                progressBar.Dock = DockStyle.Bottom;
    
                progressLabel = new Label();
                progressLabel.Dock = DockStyle.Bottom;
    
                Controls.Add(progressBar);
                Controls.Add(progressLabel);
                Controls.Add(startIndexingButton);
            }
    
            private void StartIndexingButton_Click(object sender, EventArgs e)
            {
                string folderPath = @"C:\Users\0533105132\Desktop\MyBooks"; // Replace with the path to your folder.
                string databasePath = "index.db";
    
                CreateDatabase(databasePath);
    
                // Recursively process text files in the specified folder.
                ProcessFolder(folderPath, databasePath);
    
                MessageBox.Show("Indexing complete.");
            }
    
            private void CreateDatabase(string databasePath)
            {
                using (SQLiteConnection connection = new SQLiteConnection($"Data Source={databasePath}"))
                {
                    connection.Open();
    
                    string createTableQuery = @"
                        CREATE TABLE IF NOT EXISTS WordIndex (
                            Word TEXT,
                            FilePath TEXT,
                            LineNumber INT,
                            WordPosition INT
                        );
                    ";
    
                    using (SQLiteCommand command = new SQLiteCommand(createTableQuery, connection))
                    {
                        command.ExecuteNonQuery();
                    }
                }
            }
    
            private void ProcessFolder(string folderPath, string databasePath)
            {
                string[] files = Directory.GetFiles(folderPath, "*.txt", SearchOption.AllDirectories);
                progressBar.Maximum = files.Length;
                progressBar.Value = 0;
    
                foreach (string file in files)
                {
                    progressLabel.Text = $"Processing: {Path.GetFileName(file)}";
                    Application.DoEvents(); // Update the label text
    
                    ProcessFile(file, databasePath);
    
                    progressBar.Value++;
                }
    
                progressLabel.Text = "Processing complete.";
            }
    
            private void ProcessFile(string filePath, string databasePath)
            {
                using (SQLiteConnection connection = new SQLiteConnection($"Data Source={databasePath}"))
                {
                    connection.Open();
    
                    using (SQLiteCommand command = new SQLiteCommand(connection))
                    {
                        StringBuilder insertBatch = new StringBuilder();
                        string[] lines = File.ReadAllLines(filePath, Encoding.GetEncoding(1255));
                        int lineNumber = 0;
    
                        foreach (string line in lines)
                        {
                            lineNumber++;
    
                            string[] words = Regex.Split(line, @"\W+");
    
                            foreach (string word in words)
                            {
                                if (!string.IsNullOrWhiteSpace(word))
                                {
                                    string normalizedWord = word.ToLower();
                                    insertBatch.AppendLine("INSERT INTO WordIndex (Word, FilePath, LineNumber, WordPosition) " +
                                        $"VALUES ('{normalizedWord}', '{filePath}', {lineNumber}, {insertBatch.Length});");
                                }
                            }
                        }
    
                        // Execute all insert statements in a single transaction
                        command.CommandText = insertBatch.ToString();
                        command.ExecuteNonQuery();
                    }
                }
            }
        }
    }
    
    

    מצו"ב גם תמונה של הטבלה
    d140ce75-4bab-424f-a607-6a5daefe8c5a-image.png

    גמ"ח מידע מחשבים ואופיס

    תגובה 1 תגובה אחרונה
    0
    • dovidD מנותק
      dovidD מנותק
      dovid
      ניהול
      כתב ב נערך לאחרונה על ידי dovid
      #3

      @pcinfogmach במקום לעשות הרבה משפטי INSERT עושים אחד עם הרבה ערכים, אין לי מושג למה אבל זה משפר לזכרוני ביצועים בהרבה.
      אני בחיים לא מתקשקש עם זה כי אני משתמש בספריה בשם Dapper שמה פשוט מביאים ליסט, ומבצעים Exceute, הנה שכתבתי את הפונקציה ProcessFile (עם כמה תיקונים ושיפורים) שיתאים לDapper ותבדוק אם זה מהר יותר:

      private void ProcessFile(string filePath, string databasePath)
      {
          using (SqliteConnection connection = new SqliteConnection($"Data Source={databasePath}"))
          {
              var lines = File.ReadLines(filePath, Encoding.GetEncoding(1255));
              var words = lines.SelectMany((line, index) => Regex.Matches(line, @"\b\W+\b")
                                                                 .Select(m => new { word = m.Value, filePath, lineNumber = line + 1, WordPosition = m.Index }));
      
              connection.Execute(@"INSERT INTO WordIndex(Word, FilePath, LineNumber, WordPosition) 
                                   VALUES (@word, @filePath, @lineNumber, @WordPosition)", words);
          }
      }
      
      • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
      • בכל נושא אפשר ליצור קשר dovid@tchumim.com
      תגובה 1 תגובה אחרונה
      4
      • dovidD מנותק
        dovidD מנותק
        dovid
        ניהול
        כתב ב נערך לאחרונה על ידי
        #4

        הייתה לי טעות בקוד, הנה תיקון:

        private void ProcessFile(string filePath, string databasePath)
        {
            using (SqliteConnection connection = new SqliteConnection($"Data Source={databasePath}"))
            {
                var lines = File.ReadLines(filePath, Encoding.GetEncoding(1255));
                var words = lines.SelectMany((line, index) => Regex.Matches(line, @"\b\W+\b")
                                                                   .Select(m => new { word = m.Value, filePath, lineNumber = index + 1, WordPosition = m.Index }));
         
                connection.Execute(@"INSERT INTO WordIndex(Word, FilePath, LineNumber, WordPosition) 
                                     VALUES (@word, @filePath, @lineNumber, @WordPosition)", words);
            }
        }
        • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
        • בכל נושא אפשר ליצור קשר dovid@tchumim.com
        תגובה 1 תגובה אחרונה
        0
        • dovidD dovid

          תגובה: שאלה: מה הסוד מאחורי מנוע החיפוש של בר אילן? (מבחינת תיכנות)

          @pcinfogmach
          הסברתי לך שאפשר לבנות קובץ בפורמט שמאפשר גישה אקראית, כלומר כדי לקרוא פיסת מידע 5026, לא צריך לקרוא מתחילת הקובץ אלא אפשר להזיז את מיקום הקריאה מיידית למקום הרצוי.
          כשכתבתי זאת חשבתי שאתה מתעניין תיאורטית. אם אתה מחפש מעשית כזו אפשרות, הדרך הקלה ביותר זה מסד נתונים.
          מסד נתונים זה ארגון נתונים על גבי דיסק בצורה חכמה, באופן שאפשר לדלג מרשומה לרשומה במהירות ואף לבנות מאחורי הקלעים רשימות אינדוקס. האינדקס במסד נתונים לטקסט רגיל הינו רק "מתחיל ב" ואילו ל"מכיל" או "נגמר ב" מחוייבת סריקה מלאה, אבל הסריקה המלאה הזו לא איטית בכלל, בגלל המימוש המוצלח.

          יש הרבה שיוכלו להכניס אתכם לעולם המסד נתונים לכן אני לא מפרט בעניין, לתוכנה ניידת טוב להשתמש בsqlite שזה מסד נתונים נייד (הכונה שהמנוע שלו זה ספריה שרצה כחלק מהתוכנה שלכם ולא תוכנה חיצונית) פופולרי.
          לגבי הפרוייקט שלכם תוכלו לבנות רשימת מילים, ולהכניס לטבלה את הפרטים הבאים:
          המילה, מס' ספר, מס' שורה/פסקה, מיקום
          בטבלה אחרת להכניס את הנתונים עצמם לשליפה מהירה של פסקאות של ספרים, ככה:
          מס' פסקה (מספר רץ), פסקה, מס' ספר

          על הטבלה הראשונה צריך להגדיר אינדקס על העמודה של המילה, וזהו, בעת חיפשו מילים שלמות פשוט מאתרים את המילים בטבלה ומחפשים האם ישנו רצף לפי קריטריון המרחק. אם המחפש ישים תו לתחיליות וסיומות כמו ה* בבר אילן, תצטרכו לחפש מכיל שזה סריקה מאלה, אבל זה עדיין יהיה מהר מאוד בטקסטים תורניים שיש להם סוף.
          אפשר לשפר בהרבה את כל האינדוקס אבל זה נראה לי מיותר, המהירות של בר אילן קלה להשגה לדעתי גם בטכניקות כאלה שהזכרתי.
          (הם לא משתמשים כנראה בsqlite אלא הם מימשו פרוטוקול לארגון מילים לבד, אבל בהחלט הם מבוססים על רשימת מילים).

          yossizY מנותק
          yossizY מנותק
          yossiz
          כתב ב נערך לאחרונה על ידי yossiz
          #5

          @dovid כתב בביצוע פרקטי לאינדוקס מאגר טקסט עברי:

          לתוכנה ניידת טוב להשתמש בsqlite

          אם כבר, אז יש מובנה ב-SQLITE אינדוקס טקסט לצורך חיפוש
          https://www.sqlite.org/fts5.html

          @dovid כתב בביצוע פרקטי לאינדוקס מאגר טקסט עברי:

          אם המחפש ישים תו לתחיליות וסיומות כמו ה* בבר אילן, תצטרכו לחפש מכיל שזה סריקה מאלה, אבל זה עדיין יהיה מהר מאוד בטקסטים תורניים שיש להם סוף

          בד"כ מאנדקסים רק את השורש של המילה, (אבל אין אלגוריתם פשוט לקבל את השורש, עיין כאן לפרויקט בנושא)
          אולי זה כבר בכלל:

          אפשר לשפר בהרבה את כל האינדוקס אבל זה נראה לי מיותר

          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

          תגובה 1 תגובה אחרונה
          0
          • dovidD מנותק
            dovidD מנותק
            dovid
            ניהול
            כתב ב נערך לאחרונה על ידי
            #6

            @yossiz הטכניקה שציינת מייתרת את כל הנושא (במקום לבנות אינדקסים, לשמור את התוכן כולו בעמודה עם FTS וגמרנו).
            אני לא הצעתי את זה כי לזכרוני זה טוב רק לאנגלית וגם אז זה לחיפושים "סטנדרטיים" ולא נותן חופש למפתח כמה להיות משוכלל.

            • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
            • בכל נושא אפשר ליצור קשר dovid@tchumim.com
            pcinfogmachP תגובה 1 תגובה אחרונה
            0
            • dovidD dovid

              @yossiz הטכניקה שציינת מייתרת את כל הנושא (במקום לבנות אינדקסים, לשמור את התוכן כולו בעמודה עם FTS וגמרנו).
              אני לא הצעתי את זה כי לזכרוני זה טוב רק לאנגלית וגם אז זה לחיפושים "סטנדרטיים" ולא נותן חופש למפתח כמה להיות משוכלל.

              pcinfogmachP מנותק
              pcinfogmachP מנותק
              pcinfogmach
              כתב ב נערך לאחרונה על ידי pcinfogmach
              #7

              @dovid כתב בביצוע פרקטי לאינדוקס מאגר טקסט עברי:

              @yossiz הטכניקה שציינת מייתרת את כל הנושא (במקום לבנות אינדקסים, לשמור את התוכן כולו בעמודה עם FTS וגמרנו).
              אני לא הצעתי את זה כי לזכרוני זה טוב רק לאנגלית וגם אז זה לחיפושים "סטנדרטיים" ולא נותן חופש למפתח כמה להיות משוכלל.

              תרשו לי לשאול מהי בדיוק הטכניקה החדשנית של yossiz ואיך היא מייתרת את כל הנושא?
              האם למעשה היא מייתרת או רק תיאורטית?

              הצצתי בהצעות ש @yossiz נתן ונראה שם שהוא עובד עם העקרון של lucene ובני משפחתו הבעיה עם זה שהם לא עומדים בקצב כאשר צריך להציג הרבה תוצאות. משא"כ אינדקס לבינתיים לפי מה שבדקנו דוקא כן עומד בזה. למרות שלבינתיים עוד לא מצאנו צורה מושלמת ליצור אינדקס.

              גמ"ח מידע מחשבים ואופיס

              תגובה 1 תגובה אחרונה
              0
              • dovidD מנותק
                dovidD מנותק
                dovid
                ניהול
                כתב ב נערך לאחרונה על ידי
                #8

                "חדשנית"? Full-text-search זה משהו ישן שקיים בכל מסד נתונים.
                זה קיים הרבה שנים, וזה בעצם אומר למסד נתונים לאנדקס עמודה באופן מיטבי לאיתור טקסט חלקי, כולל הבנה של התחביר (למשל להבין שרבים ויחיד זה אותה מילה).
                אני לא מכיר בכלל את היכולת הזאת, אני מניח בגלל שאני ישראלי ומעולם לא נדרשתי לאנדקס טקסט אנגלי. נו, מי אמר שזה לא עובד פרפקט בעברית? אז כנראה פעם בדקתי את זה, אבל כעת @yossiz דוחף לבדיקה נוספת ואין לי כח עבורה.
                לכן עניתי שבכל מקרה, גם אם זה עובד זה אומר שהSQL מחזיר תוצאות יפות בשאילתות אבל ללא שליטה על פרמטרי האחזור.

                • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
                • בכל נושא אפשר ליצור קשר dovid@tchumim.com
                pcinfogmachP תגובה 1 תגובה אחרונה
                1
                • dovidD dovid פיצל נושא זה ב
                • dovidD dovid

                  "חדשנית"? Full-text-search זה משהו ישן שקיים בכל מסד נתונים.
                  זה קיים הרבה שנים, וזה בעצם אומר למסד נתונים לאנדקס עמודה באופן מיטבי לאיתור טקסט חלקי, כולל הבנה של התחביר (למשל להבין שרבים ויחיד זה אותה מילה).
                  אני לא מכיר בכלל את היכולת הזאת, אני מניח בגלל שאני ישראלי ומעולם לא נדרשתי לאנדקס טקסט אנגלי. נו, מי אמר שזה לא עובד פרפקט בעברית? אז כנראה פעם בדקתי את זה, אבל כעת @yossiz דוחף לבדיקה נוספת ואין לי כח עבורה.
                  לכן עניתי שבכל מקרה, גם אם זה עובד זה אומר שהSQL מחזיר תוצאות יפות בשאילתות אבל ללא שליטה על פרמטרי האחזור.

                  pcinfogmachP מנותק
                  pcinfogmachP מנותק
                  pcinfogmach
                  כתב ב נערך לאחרונה על ידי pcinfogmach
                  #9

                  @dovid
                  אשמח אם תפשיט לי את המילים "פרמטרי האחזור". מה בדיוק החסרון בFTS המהירות? או אולי כוונתך לאיך התוצאות יוצגו?


                  למעשה ישבתי על SQLITE קצת לא יודע למה כל כך הסתבכתי לפני זה עם התכנות הבסיסי אכן זה די פשוט. (הוספתי פה גם רכיבים כדי להקל על מי שרוצה לראות את התוצאה הסופית).
                  התוצאות שקיבלתי - אינדוקס די מהיר - אבל חיפוש קצת איטי אולי שיטת החיפוש שלי לא טובה? (השתמשתי ב-סריקה מלאה כדי לאפשר חיפוש לא מדויק)

                  using System;
                  using System.Collections.Generic;
                  using System.Data;
                  using System.Data.SQLite;
                  using System.Globalization;
                  using System.IO;
                  using System.Linq;
                  using System.Reflection;
                  using System.Text;
                  using System.Text.RegularExpressions;
                  using System.Windows.Forms;
                  using static System.Windows.Forms.VisualStyles.VisualStyleElement;
                  
                  namespace WindowsFormsApp1
                  {
                      public partial class Form1 : Form
                      {
                          private System.Windows.Forms.Button buttonProcessFile;
                          private System.Windows.Forms.Button buttonViewTable;
                          private System.Windows.Forms.TextBox textBoxResult;
                          private System.Windows.Forms.ProgressBar progressBar;
                          private System.Windows.Forms.ProgressBar progressBar2;
                          private System.Windows.Forms.Button buttonSearch;
                          private DataGridView dataGridViewSearchResults;
                          private System.Windows.Forms.TextBox textBoxSearch;
                          public Form1()
                          {
                              InitializeComponent();
                              InitializeDynamicControls();
                          }
                  
                          private void InitializeDynamicControls()
                          {
                              // Create a Button for processing
                              buttonProcessFile = new System.Windows.Forms.Button();
                              buttonProcessFile.Text = "Process Text File";
                              buttonProcessFile.Location = new System.Drawing.Point(12, 12);
                              buttonProcessFile.Click += buttonProcessFile_Click;
                              this.Controls.Add(buttonProcessFile);
                  
                  
                              // Create a Button for processing
                              buttonViewTable = new System.Windows.Forms.Button();
                              buttonViewTable.Text = "View";
                              buttonViewTable.Location = new System.Drawing.Point(100, 12);
                              buttonViewTable.Click += buttonViewTable_Click;
                              this.Controls.Add(buttonViewTable);
                             
                  
                              //create progressbar 
                              //progressBar = new System.Windows.Forms.ProgressBar();
                              //progressBar.Dock = DockStyle.Bottom;
                              //this.Controls.Add(progressBar);
                  
                              //create progressbar 
                              progressBar2 = new System.Windows.Forms.ProgressBar();
                              progressBar2.Dock = DockStyle.Bottom;
                              this.Controls.Add(progressBar2);
                  
                              // Create a TextBox for displaying results
                              textBoxResult = new System.Windows.Forms.TextBox();
                              textBoxResult.Multiline = true;
                              textBoxResult.ScrollBars = ScrollBars.Vertical;
                              textBoxResult.Size = new System.Drawing.Size(400, 200);
                              textBoxResult.Location = new System.Drawing.Point(12, 50);
                              this.Controls.Add(textBoxResult);
                  
                              // Create a TextBox for entering search terms
                              textBoxSearch = new System.Windows.Forms.TextBox();
                              textBoxSearch.Location = new System.Drawing.Point(200, 12);
                              this.Controls.Add(textBoxSearch);
                  
                              // Create a Button for initiating the search
                              buttonSearch = new System.Windows.Forms.Button();
                              buttonSearch.Text = "Search";
                              buttonSearch.Location = new System.Drawing.Point(300, 12);
                              buttonSearch.Click += buttonSearch_Click;
                              this.Controls.Add(buttonSearch);
                  
                              // Create a DataGridView for displaying search results
                              dataGridViewSearchResults = new DataGridView();
                              dataGridViewSearchResults.Dock = DockStyle.Bottom;
                              this.Controls.Add(dataGridViewSearchResults);
                  
                          }
                  
                          private void buttonSearch_Click(object sender, EventArgs e)
                          {
                              string searchTerm = textBoxSearch.Text.Trim();
                              if (string.IsNullOrWhiteSpace(searchTerm))
                              {
                                  MessageBox.Show("Please enter a search term.");
                                  return;
                              }
                  
                              string databaseFilePath = GetDatabaseFilePath();
                  
                              using (SQLiteConnection connection = new SQLiteConnection($"Data Source={databaseFilePath};Version=3;"))
                              {
                                  connection.Open();
                  
                                  using (SQLiteCommand command = new SQLiteCommand("SELECT * FROM WordData WHERE Word LIKE @searchTerm;", connection))
                                  {
                                      command.Parameters.Add(new SQLiteParameter("@searchTerm", "%" + searchTerm + "%"));
                  
                                      using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
                                      {
                                          DataTable dataTable = new DataTable();
                                          adapter.Fill(dataTable);
                  
                                          // Display the search results in the DataGridView
                                          dataGridViewSearchResults.DataSource = dataTable;
                                      }
                                  }
                              }
                          }
                  
                          static string GetDatabaseFilePath()
                          {
                              // Get the path to the executable directory
                              string programFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                              return Path.Combine(programFolder, "your-database-file.sqlite");
                          }
                  
                  
                          private void buttonProcessFile_Click(object sender, EventArgs e)
                          {
                              // Create or open the SQLite database
                              string databaseFilePath = GetDatabaseFilePath();
                              using (SQLiteConnection connection = new SQLiteConnection($"Data Source={databaseFilePath};Version=3;"))
                              {
                                  connection.Open();
                  
                                  // Create a table to store word data
                                  CreateTable(connection);
                  
                                  // Let the user choose a folder to scan for text files
                                  string folderPath = GetFolderPath();
                  
                                  if (folderPath != null)
                                  {
                                      ProcessFolder(connection, folderPath);
                                      textBoxResult.AppendText("Data saved to SQLite table." + Environment.NewLine);
                                  }
                                  else
                                  {
                                      textBoxResult.AppendText("No folder selected. Exiting..." + Environment.NewLine);
                                  }
                              }
                          }
                  
                          private string GetFolderPath()
                          {
                              using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
                              {
                                  folderDialog.Description = "Select a folder to scan for text files.";
                                  DialogResult result = folderDialog.ShowDialog();
                  
                                  if (result == DialogResult.OK)
                                  {
                                      return folderDialog.SelectedPath;
                                  }
                                  else
                                  {
                                      return null; // User canceled the folder selection
                                  }
                              }
                          }
                  
                          private void ProcessFolder(SQLiteConnection connection, string folderPath)
                          {
                              string[] textFiles = Directory.GetFiles(folderPath, "*.txt", SearchOption.AllDirectories);
                  
                              progressBar2.Maximum = textFiles.Length;
                              progressBar2.Value = 0;
                              int fileCount = 0;
                  
                              foreach (string textFilePath in textFiles)
                              {
                                  ProcessTextFile(connection, textFilePath);
                                  fileCount++;
                                  progressBar2.Value++;
                              }
                  
                              textBoxResult.AppendText($"Processed {fileCount} text files and saved data to SQLite table." + Environment.NewLine);
                          }
                  
                          private void ProcessTextFile(SQLiteConnection connection, string textFilePath)
                          {
                              // Read the text file using Windows-1255 encoding
                              string[] lines = File.ReadAllLines(textFilePath, Encoding.GetEncoding(1255));
                              //progressBar.Value = 0;
                              //progressBar.Maximum = lines.Length;
                              int lineNumber = 1;
                  
                              List<WordData> wordDataList = new List<WordData>();
                  
                              // Regular expression to match Hebrew characters
                              Regex hebrewRegex = new Regex(@"\p{IsHebrew}+(?<=\p{IsHebrew})\""(?=\p{IsHebrew})\p{IsHebrew}+|\p{IsHebrew}{2,}");
                  
                              foreach (string line in lines)
                              {
                                  // Use the regular expression to match and extract Hebrew words
                                  MatchCollection matches = hebrewRegex.Matches(line);
                  
                                  foreach (Match match in matches)
                                  {
                                      string word = NormalizeHebrewText(match.Value);
                  
                                      // Add word data to the list
                                      wordDataList.Add(new WordData
                                      {
                                          Word = word,
                                          LineNumber = lineNumber,
                                          FileName = textFilePath
                                      });
                                  }
                  
                                  lineNumber++;
                                  //if (progressBar.Value < progressBar.Maximum)
                                  //{ progressBar.Value++; }
                                  
                              }
                  
                              //// Sort the words using Hebrew culture
                              //wordDataList.Sort((a, b) => string.Compare(a.Word, b.Word, new CultureInfo("he-IL"), CompareOptions.None));
                  
                              // Insert all word data into the SQLite table at once
                              InsertWordDataBatch(connection, wordDataList);
                  
                              textBoxResult.AppendText($"{textFilePath} Processed {lines.Length} lines and saved data to SQLite table." + Environment.NewLine);
                          }
                  
                          private string NormalizeHebrewText(string text)
                          {
                              // Normalize Hebrew text (e.g., remove diacritics)
                              // You may need to implement this normalization based on your specific requirements.
                              // Example: Normalize to remove diacritics (NFD normalization)
                              text = new string(text.Normalize(NormalizationForm.FormD).Where(c => char.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark).ToArray()); // Normalize Hebrew text.
                              return text; // Return the normalized text.
                          }
                  
                  
                  
                  
                          static void CreateTable(SQLiteConnection connection)
                          {
                              using (SQLiteCommand command = new SQLiteCommand(
                                  "CREATE TABLE IF NOT EXISTS WordData (Word TEXT, LineNumber INT, FileName TEXT);", connection))
                              {
                                  command.ExecuteNonQuery();
                              }
                          }
                  
                          static void InsertWordDataBatch(SQLiteConnection connection, List<WordData> wordDataList)
                          {
                              using (SQLiteCommand command = new SQLiteCommand(connection))
                              {
                                  // Start a transaction for batch insert
                                  using (var transaction = connection.BeginTransaction())
                                  {
                                      command.CommandText = "INSERT INTO WordData (Word, LineNumber, FileName) VALUES (@word, @lineNumber, @fileName);";
                                      command.Parameters.Add(new SQLiteParameter("@word", DbType.String));
                                      command.Parameters.Add(new SQLiteParameter("@lineNumber", DbType.Int32));
                                      command.Parameters.Add(new SQLiteParameter("@fileName", DbType.String));
                  
                                      foreach (var wordData in wordDataList)
                                      {
                                          command.Parameters["@word"].Value = wordData.Word;
                                          command.Parameters["@lineNumber"].Value = wordData.LineNumber;
                                          command.Parameters["@fileName"].Value = wordData.FileName;
                  
                                          // Add the command to the transaction
                                          command.ExecuteNonQuery();
                                      }
                  
                                      // Commit the transaction to perform the batch insert
                                      transaction.Commit();
                                  }
                              }
                          }
                  
                          private void buttonViewTable_Click(object sender, EventArgs e)
                          {
                              string databaseFilePath = GetDatabaseFilePath();
                  
                              using (SQLiteConnection connection = new SQLiteConnection($"Data Source={databaseFilePath};Version=3;"))
                              {
                                  connection.Open();
                  
                                  using (SQLiteCommand command = new SQLiteCommand("SELECT * FROM WordData;", connection))
                                  {
                                      using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
                                      {
                                          DataTable dataTable = new DataTable();
                                          adapter.Fill(dataTable);
                  
                                          // Create a new form to display the table
                                          Form tableForm = new Form();
                                          tableForm.Text = "WordData Table Contents";
                  
                                          // Create a DataGridView control and set its properties
                                          DataGridView dataGridView = new DataGridView();
                                          dataGridView.Dock = DockStyle.Fill;
                                          dataGridView.DataSource = dataTable;
                  
                                          // Add the DataGridView to the form
                                          tableForm.Controls.Add(dataGridView);
                  
                                          // Show the form as a dialog
                                          tableForm.ShowDialog();
                                      }
                                  }
                              }
                          }
                  
                  
                  
                  
                          public class WordData
                          {
                              public string Word { get; set; }
                              public int LineNumber { get; set; }
                              public string FileName { get; set; }
                          }
                  
                      }
                  }
                  

                  ועוד שאלה:

                  @dovid כתב בביצוע פרקטי לאינדוקס מאגר טקסט עברי:

                  לגבי הפרוייקט שלכם תוכלו לבנות רשימת מילים, ולהכניס לטבלה את הפרטים הבאים:
                  המילה, מס' ספר, מס' שורה/פסקה, מיקום
                  בטבלה אחרת להכניס את הנתונים עצמם לשליפה מהירה של פסקאות של ספרים, ככה:
                  מס' פסקה (מספר רץ), פסקה, מס' ספר

                  לא הצלחתי למצוא את המכנה המשותף בין שני הטבלאות שמאפשר לי להצליב בין המידע שאקבל מטבלה א' לצורך טבלה ב'.
                  אולי עם דוגמא קצרה אוכל לרדת לסוף דעתך.

                  גמ"ח מידע מחשבים ואופיס

                  תגובה 1 תגובה אחרונה
                  0
                  • dovidD מנותק
                    dovidD מנותק
                    dovid
                    ניהול
                    כתב ב נערך לאחרונה על ידי dovid
                    #10

                    @pcinfogmach הבאתי קוד בעבר ולא הצלחת להטמיע אותו,
                    אני צריך ערובה שהשקעתי בתשובה לא תירד לטמיון.
                    גם מאוד מפריע לי הפיזור שלך בשאלות, זה נראה שאתה בלחץ אטומי. תברר דבר דבר, תעיין תבין ותחכים.
                    יש המון בעיות בקוד שלך, דבר ראשון החיפוש הוא לא הגיוני, הטבלה הרי מכילה מילים בודדות, לא ביטוי (של יותר ממילה). צריך לקחת את קלט החיפוש ולפצל אותו למילים. כל מילה של המחפש היא בברירת מחדל מילה שלמה, אם הוא מחפש "אבא אמר" הוא רוצה "אבא" והוא רוצה "אמר". להניח מראש שהוא רוצה אמרו, זה גם לא נכון וגם מבחינת פיתוח זה קפיצה. הרעיון הוא לחפש בטבלה אבא בלי שום % וגם אמר, ולמצוא את אלה שהכי קרובים מבחינת מיקום.
                    (בהמשך תאפשר למשתמש לשים אסימונים כמו כוכבית וככה לומר שהוא רוצה סיומות, ואם אתה רוצה רק דקדוקי תצטרך לשבת על טבלת המילים ולעבוד עליה רציני, מוקם כעת לדעתי).

                    • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
                    • בכל נושא אפשר ליצור קשר dovid@tchumim.com
                    pcinfogmachP תגובה 1 תגובה אחרונה
                    0
                    • dovidD dovid

                      @pcinfogmach הבאתי קוד בעבר ולא הצלחת להטמיע אותו,
                      אני צריך ערובה שהשקעתי בתשובה לא תירד לטמיון.
                      גם מאוד מפריע לי הפיזור שלך בשאלות, זה נראה שאתה בלחץ אטומי. תברר דבר דבר, תעיין תבין ותחכים.
                      יש המון בעיות בקוד שלך, דבר ראשון החיפוש הוא לא הגיוני, הטבלה הרי מכילה מילים בודדות, לא ביטוי (של יותר ממילה). צריך לקחת את קלט החיפוש ולפצל אותו למילים. כל מילה של המחפש היא בברירת מחדל מילה שלמה, אם הוא מחפש "אבא אמר" הוא רוצה "אבא" והוא רוצה "אמר". להניח מראש שהוא רוצה אמרו, זה גם לא נכון וגם מבחינת פיתוח זה קפיצה. הרעיון הוא לחפש בטבלה אבא בלי שום % וגם אמר, ולמצוא את אלה שהכי קרובים מבחינת מיקום.
                      (בהמשך תאפשר למשתמש לשים אסימונים כמו כוכבית וככה לומר שהוא רוצה סיומות, ואם אתה רוצה רק דקדוקי תצטרך לשבת על טבלת המילים ולעבוד עליה רציני, מוקם כעת לדעתי).

                      pcinfogmachP מנותק
                      pcinfogmachP מנותק
                      pcinfogmach
                      כתב ב נערך לאחרונה על ידי pcinfogmach
                      #11

                      @dovid כתב בביצוע פרקטי לאינדוקס מאגר טקסט עברי:

                      אני צריך ערובה שהשקעתי בתשובה לא תירד לטמיון.
                      גם מאוד מפריע לי הפיזור שלך בשאלות, זה נראה שאתה בלחץ אטומי. תברר דבר דבר, תעיין תבין ותחכים.

                      לגבי הערובה אני נמצא במקום של התלמיד כך שהשאלה היא האם התלמיד יכול להגיד לרב שמה שהוא אומר זה יעיל לו או לא? לבינתיים לא איכזבת אז אני מאמין בך. אם נגיע לתוצאות שאפשר להשתמש בהם ברור שאשתמש בזה.
                      האמת היא שאני עדיין מנסה לעכל את זה שיש פה מישהו שמוכן ככה לעזור בחפשיות (אם לא אשגע אותו מדאי הרבה). VBA הייתי צריך ללמוד לבד והדרך הייתה מפותלת ומעניינת. (היה לי שם חברותא אבל לא "רב").

                      לחץ אטומי ממש לא - פשוט ככה הראש שלי עובד אני מבין דברים הפוך, לא מההתחלה לסוף אלא מהסוף להתחלה הריכוז שלי ג"כ עובד בצורה מעניינת כלומר שהריכוז שלי מאוד ממוקד - סוג של חפרפרת שפשוט נדבק על משהו עד שהוא מגיע לאשורו (גם הנקיונות שלי לשבת נראים ככה - וזה משגע את אישתי...) (מכיון שראית את התפתחות חלק מהפוסטים שלי אני חושב שאתה יכול לקבל תמונה קצת על מה אני מדבר).
                      כל זה לא אומר שאני לא יכול לעבוד בצורה מסודרת אם צריך. אשתדל להישאר כאן בפוסט זה ולא לפזר שאלות לכל עבר.

                      דבר ראשון החיפוש הוא לא הגיוני, הטבלה הרי מכילה מילים בודדות, לא ביטוי (של יותר ממילה).

                      את זה אני יודע - הבדיקה היתה על חיפוש של מילה אחת כדי לבדוק מהירות שליפה.

                      לגבי הסימות וכו' הסיבה היא בגלל שאני אוהב לבדוק מקרי קצה לפני שאני נכנס לעובי הקורה. אולי אתה צודק ואי אפשר לשפוט יעילות לפי מקרי קצה. למרות שבפרוייקט שלי השימוש בסיומות וכו' אמור להיות די מצוי.

                      למעשה עשיתי עכשיו בדיקה ללא הסיומות ולא היה שום הבדל מצד המהירות

                      command.Parameters.Add(new SQLiteParameter("@searchTerm", searchTerm));
                      

                      גמ"ח מידע מחשבים ואופיס

                      תגובה 1 תגובה אחרונה
                      2
                      • dovidD מנותק
                        dovidD מנותק
                        dovid
                        ניהול
                        כתב ב נערך לאחרונה על ידי
                        #12

                        @pcinfogmach זה טוב שאתה מאמין בי, אבל אני גם צריך להאמין בך. ציינתי שאת הקוד שלי עם הDapper לא הצלחת להטמיע.

                        מאוד משונה שהמהירות לא השתנתה, זה כמעט לא מציאותי. אני הייתי שמח ללבן איתך יחד את הנושא, פנה אלי במייל.

                        • מנטור אישי בתכנות והמסתעף – להתקדם לשלב הבא!
                        • בכל נושא אפשר ליצור קשר dovid@tchumim.com
                        תגובה 1 תגובה אחרונה
                        3
                        תגובה
                        • תגובה כנושא
                        התחברו כדי לפרסם תגובה
                        • מהישן לחדש
                        • מהחדש לישן
                        • הכי הרבה הצבעות


                        בא תתחבר לדף היומי!
                        • התחברות

                        • אין לך חשבון עדיין? הרשמה

                        • התחברו או הירשמו כדי לחפש.
                        • פוסט ראשון
                          פוסט אחרון
                        0
                        • דף הבית
                        • קטגוריות
                        • פוסטים אחרונים
                        • משתמשים
                        • חיפוש
                        • חוקי הפורום