Самый быстрый способ записать все 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