Самый быстрый способ записать все DocIds и FileNames из dtSearch в базу данных SQL

Я использую dtSearch в сочетании с базой данных SQL и хотел бы вести таблицу, которая включает все DocIds и связанные с ними имена файлов. Оттуда я добавлю столбец с моим внешним ключом, чтобы позволить мне комбинировать текстовый поиск и поиск в базе данных.

У меня есть код, чтобы просто вернуть все записи в индексе и добавить их одну за другой в БД. Это, однако, требует FOREVER и не решает проблему простого добавления новых записей по мере их добавления в индекс. Но на всякий случай это помогает:

MyDatabaseContext db = new StateScapeEntities();
IndexJob ij = new dtSearch.Engine.IndexJob();

ij.IndexPath = @"d:\myindex";

IndexInfo indexInfo = dtSearch.Engine.IndexJob.GetIndexInfo(@"d:\myindex");

bool jobDone =   ij.Execute();

SearchResults sr = new SearchResults();

uint n = indexInfo.DocCount;

for (int i = 1; i <= n; i++)
{
    sr.AddDoc(ij.IndexPath, i, null);
}

for (int i = 1; i <= n; i++)
{
    sr.GetNthDoc(i - 1);
        //IndexDocument is defined elsewhere
        IndexDocument id = new IndexDocument();
        id.DocId = sr.CurrentItem.DocId;
        id.FilePath = sr.CurrentItem.Filename;

        if (id.FilePath != null)
        {
            db.IndexDocuments.Add(id);
            db.SaveChanges();           
        }   
}

4 ответа

Решение

Итак, я использовал часть ответа user2172986, но объединил его с некоторым дополнительным кодом, чтобы получить решение моего вопроса. Я действительно должен был установить флаг dtsKeepExistingDocIds в моей процедуре обновления индекса. Оттуда я только хотел добавить недавно созданные DocIds в свою базу данных SQL. Для этого я использовал следующий код:

string indexPath = @"d:\myindex"; 

        using (IndexJob ij = new dtSearch.Engine.IndexJob())
        {
            //make sure the updated index doesn't change DocIds
            ij.IndexingFlags = IndexingFlags.dtsIndexKeepExistingDocIds;
            ij.IndexPath = indexPath;
            ij.ActionAdd = true;
            ij.FoldersToIndex.Add( indexPath + "<+>");
            ij.IncludeFilters.Add( "*");
            bool jobDone = ij.Execute();
        }
        //create a DataTable to hold results
        DataTable newIndexDoc = MakeTempIndexDocTable(); //this is a custom method not included in this example; just creates a DataTable with the appropriate columns

        //connect to the DB;
        MyDataBase db = new MyDataBase(); //again, custom code not included - link to EntityFramework entity

        //get the last DocId in the DB?
        int lastDbDocId = db.IndexDocuments.OrderByDescending(i => i.DocId).FirstOrDefault().DocId;

        //get the last DocId in the Index
        IndexInfo indexInfo = dtSearch.Engine.IndexJob.GetIndexInfo(indexPath);

        uint latestIndexDocId = indexInfo.LastDocId;

        //create a searchFilter
        dtSearch.Engine.SearchFilter sf = new SearchFilter();

        int indexId = sf.AddIndex(indexPath);


        //only select new records (from one greater than the last DocId in the DB to the last DocId in the index itself
        sf.SelectItems(indexId, lastDbDocId + 1, int.Parse(latestIndexDocId.ToString()), true);

        using (SearchJob sj = new dtSearch.Engine.SearchJob())
        {
           sj.SetFilter(sf);
           //return every document in the specified range (using xfirstword)
           sj.Request = "xfirstword";
           // Specify the path to the index to search here
           sj.IndexesToSearch.Add(indexPath);


          //additional flags and limits redacted for clarity

           sj.Execute();

           // Store the error message in the status
           //redacted for clarity



           SearchResults results = sj.Results;
           int startIdx = 0;
           int endIdx = results.Count;
           if (startIdx==endIdx)
               return;


           for (int i = startIdx; i < endIdx; i++)
           {
               results.GetNthDoc(i);

               IndexDocument id = new IndexDocument();
               id.DocId = results.CurrentItem.DocId;
               id.FileName= results.CurrentItem.Filename;

               if (id.FileName!= null)
               {

                   DataRow row = newIndexDoc.NewRow();

                   row["DocId"] = id.DocId;
                   row["FileName"] = id.FileName;

                   newIndexDoc.Rows.Add(row);
               }


           }

           newIndexDoc.AcceptChanges();

           //SqlBulkCopy
           using (SqlConnection connection =
                  new SqlConnection(db.Database.Connection.ConnectionString))
           {
               connection.Open();

               using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
               {
                   bulkCopy.DestinationTableName =
                       "dbo.IndexDocument";

                   try
                   {
                       // Write from the source to the destination.
                       bulkCopy.WriteToServer(newIndexDoc);
                   }
                   catch (Exception ex)
                   {
                       Console.WriteLine(ex.Message);
                   }
               }
           }

           newIndexDoc.Clear();
           db.UpdateIndexDocument();
        }

Чтобы сохранить DocId в индексе, вы должны использовать флаг dtsIndexKeepExistingDocIds в IndexJob

Вы также можете посмотреть Справочник программиста механизма получения текста dtSearch при изменении DocID.

  • Когда документ добавляется в индекс, ему присваивается DocId, а DocIds всегда нумеруются последовательно.

  • Когда документ переиндексируется, старый DocId отменяется и назначается новый DocId.

  • Когда индекс сжимается, все DocIds в индексе перенумеровываются, чтобы удалить отмененные DocIds, если в IndexJob не установлен флаг dtsIndexKeepExistingDocIds.

  • Когда индекс объединяется с другим индексом, DocIds в целевом индексе никогда не изменяются. Всем документам, объединенным с целевым индексом, будут назначены новые последовательные пронумерованные DocIds, если (a) флаг dtsIndexKeepExistingDocIds не установлен в IndexJob и (b) индексы не имеют перекрывающихся диапазонов идентификаторов документов.

Для повышения скорости вы можете выполнить поиск по слову " xfirstword " и получить все документы в индексе.

Вы также можете посмотреть часто задаваемые вопросы Как получить все документы в индексе

Вот мое новое решение с методом AddDoc из интерфейса SearchResults:

Сначала получите StartingDocID и LastDocID из IndexInfo и выполните цикл следующим образом:

function GetFilename(paDocID: Integer): String;    
var
  lCOMSearchResults:       ISearchResults;
  lSearchResults_Count:    Integer;
begin
  if Assigned(prCOMServer) then
  begin
    lCOMSearchResults := prCOMServer.NewSearchResults as ISearchResults;
    lCOMSearchResults.AddDoc(GetIndexPath(prIndexContent), paDocID, 0);
    lSearchResults_Count := lCOMSearchResults.Count;

    if lSearchResults_Count = 1 then
    begin
      lCOMSearchResults.GetNthDoc(0);
      Result := lCOMSearchResults.DocDetailItem['_Filename'];
    end;
  end;
end
Другие вопросы по тегам