65.9K
CodeProject 正在变化。 阅读更多。
Home

在 AWS 上使用 dtSearch(EC2 & EBS)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2019年7月15日

CPOL

13分钟阅读

viewsIcon

14485

downloadIcon

78

本文将演示如何使用 Elastic Cloud Compute (EC2) 来创建虚拟机并在其上部署应用程序,以及使用 Elastic Block Store (EBS) 来创建虚拟磁盘卷并将其附加到 EC2 实例。

想象一下,利用 dtSearch 引擎的强大功能来索引和搜索 Microsoft Office 文档、PDF、电子邮件和其他数据,同时拥有 Amazon Web Services (AWS) 的全球可访问性和存储容量。本文将演示如何使用 Elastic Cloud Compute (EC2) 来创建虚拟机并在其上部署应用程序,以及使用 Elastic Block Store (EBS) 来创建虚拟磁盘卷并将其附加到 EC2 实例。

我们将使用 dtSearch 引擎创建一个控制台应用程序并将其部署到 EC2。我们将使用该控制台应用程序来创建数据集合的索引,然后利用该索引来发挥 dtSearch 引擎的高级搜索功能。

项目先决条件

在设置项目时,我们将创建一个 EC2 实例并向该实例附加两个 EBS 卷。一个 EBS 卷将包含要索引的数据,另一个 EBS 卷将存储已完成的索引。请注意,源材料和索引都可以保存在同一个 EBS 卷上。但是,由于源材料或实际应用程序的需求可能需要单独的存储,因此我们将演示如何将索引存储在单独的 EBS 卷上。

本文假定我们已经拥有一个 AWS 账户,因此请先登录到控制台。一旦进入控制台,我们就可以看到可用的服务列表,最近使用的服务位于顶部以便于访问。

请注意,EBS 不存在于 EC2 之外,因为您无法在 EC2 实例的上下文之外使用 EBS 卷。要创建 EC2 实例以及本项目所需的 EBS 卷,请从 EC2 控制板开始。您可以在“计算”部分找到 EC2 项。

创建 EC2 实例

在 EC2 控制板中,使用“启动实例”按钮创建新实例。

本次演示我们将使用 Microsoft Windows Server 2019 Base 镜像。

AWS 控制台会引导我们完成设置 EC2 实例所需的步骤。我们可以在屏幕顶部看到这些步骤列表。

在此示例中,我们将选择 t2.micro 实例类型。请注意,此实例包含一个 EBS 存储卷。

选择第 3 步的默认设置——所有默认设置都适用于我们正在做的事情。

在第 4 步中,我们可以添加更多存储。在这里,我们将为索引设置第二个 EBS 卷。

对于这个特定的演示,默认的 8 GB 卷绰绰有余。有关不同类型的 EBS 卷的更多信息,请参阅EBS 卷类型

我们不需要添加任何自定义标签,因此跳过第 5 步。

所有 EC2 计算机都分配有安全组。向导创建的默认类型包含一个用于 RDP 的防火墙规则,我们将使用此规则来连接和控制启动后的计算机。要将此规则限制为我们自己的计算机,请从选择框中选择“我的 IP”选项,向导将加载 IP。

单击“查看并启动”按钮以导航到第 7 步。然后单击“启动实例”按钮。控制台将显示一个询问密钥对的新框。

有关 EC2 密钥对的详细信息,请参阅Amazon EC2 密钥对文档。如果我们已有一个 EC2 密钥对,则可以使用它。我们也可以选择现在创建一个密钥对。如果我们现在创建一个,浏览器应该会自动下载私钥。

在应用程序中使用 dtSearch API

我们创建了一个非常简单的控制台应用程序项目,以演示如何将 dtSearch 引擎连接到应用程序并使用该搜索引擎。我们将在此处详细介绍该应用程序的一些细节。下载项目源代码即可开始。

首先在 Visual Studio 中打开示例项目。为了从应用程序中使用 dtSearch 引擎,我们将需要部署dtSearchEngine.dll文件。右键单击项目,然后从上下文菜单中选择“添加”>“现有项”。

为了本文的需要,我们在代码中包含了 lib 文件夹,并在项目文件中使用了相对引用。对于您自己构建项目,应直接从 dtSearch 安装文件夹/lib加载。如果您正在构建一个 .NET Framework C# 应用程序(例如示例中的控制台应用程序),则导航到/lib/engine/win/x64并从该文件夹中选择 DLL。

请确保选择“添加为链接”,这样项目将引用安装位置的 DLL(这样我们就不会在各种项目位置中出现 DLL 的副本)。

我们希望将 DLL 复制到构建文件夹,因此我们必须更新项目中的 DLL 属性。将“生成操作”设置为“内容”,并将“复制”属性设置为“如果较新则复制”。

接下来,我们将一个对 dtSearchNetStdApi.dll 的引用添加到项目依赖项中。右键单击并选择“添加引用”,然后单击“浏览”并在/lib/engine/NetStd/文件夹中找到 DLL。单击“确定”。这就是我们将 dtSearch 引擎连接到程序所需的所有操作。

程序启动,检查引擎

现在让我们看看程序本身。我们将先看一些支持性内容,然后再逐步构建到程序。但首先,我们需要一个检查来确保 dtSearch 引擎可访问。打开示例应用程序并查看“VersionInfo.cs”。

private void GetEngineVersion()
{
  try
  {
    dtSearch.Engine.Server server = new dtSearch.Engine.Server();
    EngineMajorVersion = server.MajorVersion;
    EngineMinorVersion = server.MinorVersion;
    EngineBuild = server.Build;
    EngineVersion = server.MajorVersion + 
                    "." + 
                    server.MinorVersion + 
                    " Build " + 
                    server.Build;
    LoadedOK = true;
  }
  //code to catch errors if dtSearch.Engine fails to load not shown
}

此函数调用 dtSearch 引擎,如果加载失败,则有 catch 处理程序来适当地设置 LoadError 状态。我们的应用程序将调用此函数并检查该条件以确保其正确加载。

关闭该文件并打开 IndexResultItem.cs

public IndexResultItem(IndexFileInfo info, MessageCode updateType)
{
  Filename = info.Name;
  Location = info.Location;

  if (updateType == MessageCode.dtsnIndexFileOpenFail)
  {
    Error = info.OpenFailMessage;
    Detail = "Not indexed: " + Error;
  }
  else if (updateType == MessageCode.dtsnIndexFileDone)
  {
    Success = true;
    WordCount = info.WordCount;
    Detail = info.Type + " " + info.WordCount + " words";
  }
  else if (updateType == MessageCode.dtsnIndexFileEncrypted)
  {
    Encrypted = true;
    Detail = "Encrypted";
  }
}

构造函数期望一个 IndexFileInfo 项。如果我们选择该项并按 F12(或右键单击并选择“转到定义”),我们可以看到该类中可用的项。dtSearch 引擎保留有关正在索引的每个项的大量信息。有关详细信息,请参阅IndexFileInfo 成员文档。

返回 IndexResultItem.cs 并对 MessageCode 执行相同的“转到定义”步骤。我们可以看到大约有 40 种不同的代码。有关这些代码的详细信息,请参阅dtSearch.Engine.MessageCode 枚举文档。我们将在项目的后期使用其中一些代码。

处理来自引擎的状态更新

接下来,我们来看 IndexStatusHandler.cs。我们可以看到它实现了 dtSearch.Engine.IIndexStatusHandler 接口,该接口有两个方法:CheckForAbortOnProgressUpdate

class IndexStatusHandler : IIndexStatusHandler

dtSearch 引擎调用 CheckForAbort 来查看是否应因我们确认为致命的某种故障或允许用户停止的操作而退出。在此类中,我们将看到 Cancelled 和 Stopped 是两个布尔标志。在 CheckForAbort 函数中,我们看到 Cancelled 用于突然终止进程,而 Stopped 用于在进程完成当前任务时退出进程。

public AbortValue CheckForAbort()
{
  if (Cancelled)
    return AbortValue.CancelImmediately;
  else if (Stopped)
    return AbortValue.Cancel;
  else
    return AbortValue.Continue;
}

OnProgressUpdate 函数接收一个 IndexProgressInfo,其中包含有关索引更新当前状态的信息。

public void OnProgressUpdate(IndexProgressInfo info)
{
  // sample of putting something in the log. 
  Server.AddToLog("Index progress: " + info.PercentDone + "%");

  // call the progress reporter (dtSearchApp) when info.PercentDone changes
  if ((ProgressReporter != null) && info.PercentDone != 
      percentDoneReported && !Cancelled)
  {
    percentDoneReported = info.PercentDone;
    ProgressReporter.Report(info.PercentDone);
  }
  ...

有关详细信息,请参阅 dtSearch 文档中的IndexProgressInfo 成员

如果查看 IndexProgressInfo 的类声明,我们可以看到在顶部有一个关联的 IndexFileInfo 对象,因此这些进度项与正在索引的特定文件有关。

public class IndexProgressInfo
{
  public IndexFileInfo File;
 
  public IndexProgressInfo();
 
  public uint CurrMergePercent { get; set; }
  public uint EstRemainingSeconds { get; set; }
  public uint ElapsedSeconds { get; set; }
  ... //more
}

OnProgressUpdate 中的 ProgressReporter 项只是一个传入的函数,用于报告 info.PercentDone 属性的变化。

在进度报告下方,有一个开关处理 info.UpdateType 属性。

switch (info.UpdateType)
{
    case MessageCode.dtsnIndexFileDone:
    case MessageCode.dtsnIndexFileOpenFail:
    case MessageCode.dtsnIndexFileEncrypted:
        if (FileList.Count < MaxListSize)
            FileList.Add(new IndexResultItem(info.File, info.UpdateType));
        break;
    case MessageCode.dtsnIndexDone:
        Result = info;
        break;
    default:
        break;
}

还记得前面的 MessageCode 吗?UpdateType 属性是 MessageCode 类型,因此我们可以在这里对大约 40 个项目中的任何一个做出反应。在此示例中,它通过将信息添加到 FileList 来处理指示文件已完成的项目。生产应用程序需要更强大的机制来处理可能数百万个文件的存储信息。

索引作业

SampleIndexJob.cs 中,我们可以看到该文件扩展了 dtSearch.EngineIndexJob

public class IndexJob : JobBase

{...

与之前一样,我们可以使用“转到定义”来查看 IndexJob 可用的属性以及我们可以覆盖的一个且仅有的方法:Execute()。有关这些成员的完整文档可以在IndexJob 成员下找到。

在这个简单的例子中,我们只会涉及其中几个成员。我们将覆盖 Execute,并设置几个选项,此外还会告诉 dtSearch 引擎要索引哪个文件夹。

返回 SampleIndexJob.cs 并查看构造函数。它接受我们之前讨论过的进度处理程序。IndexStatusHander 需要它,所以在构造函数中我们将其传递过去。dtSearch.Engine.IndexJob.StatusHandler 期望 IndexStatusHander,因此我们在此处为其赋值。

public SampleIndexJob(Action aProgressHandler = null)
{
  indexStatusHandler = new IndexStatusHandler();
  if (aProgressHandler != null)
    indexStatusHandler.ProgressReporter = new Progress(aProgressHandler);

  StatusHandler = indexStatusHandler;
}

public override bool Execute()
{
  indexStatusHandler.BeforeExecute();

  return base.Execute();
}

接下来,我们看到对 IndexJob.Execute() 函数的覆盖。它调用 indexStatusHandler.BeforeExecute() 来清除上一个运行中遗留的数据。这使得程序在单次运行中可以执行多个索引作业。

此类中的其他项目是不言自明的。

调用作业

最后,实际工作从这里开始。打开 dtSearchApp.cs 文件。

Run() 函数是索引作业的主入口点。首先,它调用 VersionInfo 对象以确保 dtSearch 引擎存在。如果加载失败,我们将退出。

然后,程序询问要执行哪个操作:(I)索引,(S)搜索,还是(Q)退出。我们先看(I)索引。

BuildIndex() 函数询问要索引的文档在哪里。在此示例中,我们在“docs”文件夹中提供莎士比亚的作品。然后它会询问应该存储索引的文件夹。在此示例中,我们希望将索引存储在另一个 EBS 卷上。

以下部分创建 SampleIndexJob 类的一个新实例,并传入“ShowProgress”函数(这是我们的 ProgressReporter 函数)。然后设置我们需要的选项:IndexPathActionCreateActionAdd。然后我们将要索引的文件夹添加到 FoldersToIndex。(FoldersToIndex 是一个 List<string>,因此我们可以添加任意数量的不同文件夹,放在我们系统的任何位置。)然后调用 Execute()

// create a job to build the index
using (SampleIndexJob job = new SampleIndexJob(ShowProgress))
{
  // fill in the options
  job.IndexPath = indexPath;
  job.ActionCreate = true;
  job.ActionAdd = true;

  // put in one (or more) folders to index
  job.FoldersToIndex.Add(docsPath);
  
  // At last, some activity!
  job.Execute();

  // indexing finished here, post results
  var fileList = job.GetFilesIndex();
  int logCount = 0;
  Console.WriteLine(Environment.NewLine + "Results:");
  foreach (var file in fileList)
  {
    Console.WriteLine(file.Filename + " " + file.Detail);
    logCount++;
    if (logCount > 25)
    {
      if (AskYesNo("See more items?"))
        logCount = 0;
      else
        break;
    }
  }
  Console.WriteLine(job.SummarizeIndexResult());
}
Console.WriteLine("Indexing complete");

就是这样。创建一个索引状态处理程序(IndexStatusHander),扩展 IndexJob (SampleIndexJob),提供一个用于获取运行所需信息的 UI,并调用作业的 Execute() 函数。这是在您自己的应用程序中使用 dtSearch 引擎的最简单情况。

我们还有最后一步,将其连接到 Main()

打开 Program.cs,您将看到这里只需要创建一个 dtSearchApp 实例并调用 Run()

部署到 AWS

此控制台应用程序将在 EC2 实例上运行,无需任何特殊修改。我们需要生成发布版本,将其复制到 EC2 实例,然后调用 dotnet 来运行它。将 Visual Studio 目标切换到 Release,然后选择“全部重新生成”。然后将文件从输出目录复制到 EC2 实例。

我们使用远程桌面连接来连接到 EC2。我们通过从 AWS 下载文件来获取连接详细信息。

重新登录 AWS,找到 EC2 控制板,选择要使用的 EC2 实例,然后单击“连接”按钮。将出现一个新对话框,允许我们下载连接到 EC2 实例所需的 RDP 文件。我们也可以单击按钮来获取该计算机的管理员密码。

下载文件并双击它以打开远程桌面连接。展开详细信息,确保启用了剪贴板共享,并使用 AWS 提供的密码进行连接。

当我们首次连接到计算机时,第二个驱动器可能需要格式化并分配一个驱动器号。我们使用了卷名“IndexStore”并分配了 H: 驱动器。这就是我们在程序中设置为默认索引驱动器的内容。Windows 资源管理器将显示两个驱动器。


打开 C: 驱动器,创建一个名为“dtSearch”的文件夹,然后打开它。切换回本地计算机,将文件从构建文件夹复制,然后粘贴到 EC2 中的窗口中。

切换回本地计算机,将 zip 文件中的“docs”文件夹复制,然后粘贴到 EC2 中的窗口中。文件夹应如下所示

我们可以使用命令行通过 dotnet 来运行 .NET Core 控制台应用程序。在 dtSearch 文件夹中打开一个命令窗口(Shift + 右键单击)并运行此命令

dotnet dtSearchConsoleApp.dll

程序会要求输入文档和索引路径。结果将显示在窗口中。

目标文件夹将被创建,并且索引将放置在我们指定的索引路径中。

查看结果

现在我们能够构建索引了,就可以使用该索引进行搜索了。SearchIndex() 函数执行此部分。

// Run search on the index at the indexPath
private void SearchIndex()
{
    // gather info and init
    indexPath = GetIndexPath();
    searchRequest = GetInput("Search for", searchRequest);
    if (searchResults != null)
        searchResults.Dispose();
    searchResults = new SearchResults();

    // create a search job, set the parameters, and execute it
    using (SearchJob searchJob = new SearchJob())
    {
        searchJob.Request = searchRequest;
        searchJob.MaxFilesToRetrieve = 10;
        searchJob.IndexesToSearch.Add(indexPath);
        searchJob.SearchFlags = SearchFlags.dtsSearchDelayDocInfo;
        searchJob.Execute(searchResults);
    }
    ShowResults();
}

SearchIndex() 请求一个 indexPath 并要求用户输入搜索文本。它创建 SearchResults 类的一个新实例。然后我们创建一个新的 SearchJob 并设置参数,包括搜索文本、索引路径和搜索标志。

有关 SearchJob 的详细信息可以在此处找到。有关搜索标志的更多信息,请参阅文档中的SearchFlags 枚举

搜索的最后一步是显示结果。为此,我们创建了一个单独的函数。

// Show the results of search on the console window
private void ShowResults()
{
    Console.WriteLine(searchResults.TotalHitCount + 
        " Hits in " + searchResults.TotalFileCount + " Files");
    SearchResultsItem item = new SearchResultsItem();
    for (int i = 0; i < searchResults.Count; ++i)
    {
        searchResults.GetNthDoc(i, item);
        Console.WriteLine(item.HitCount + " " + item.Filename);
    }
}

ShowResults() 函数遍历 SearchResults 项,并仅输出每个项的 FilenameHitCountSearchResults 项对象中还有许多其他属性,我们可以在 SearchResultsItem 成员文档中看到。

看到搜索结果固然很好,但在生产应用程序中,用户期望通过 Web 界面访问搜索结果。幸运的是,dtSearch 提供了一个示例项目,演示了如何从 ASP.NET Core Web 应用程序中使用 dtSearch 索引。如果我们查看 dtSearch 安装目录,会在examples\NetStd\WebDemo文件夹中找到该应用程序。接下来,阅读使用 dtSearch® ASP.NET Core WebDemo 示例应用程序以更深入地了解 WebDemo 应用程序的工作原理。最后,我们可以在search.dtsearch.com上看到 WebDemo 的实际应用。

总结

在此演示中,我们创建了一个带有第二个 EBS 存储卷的 EC2 实例。我们创建了一个新的控制台项目,并学习了如何附加 dtSearchEngine DLL,使其包含在输出中。我们还添加了一个供程序使用的 dtSearchNetStdApi 引用。

我们回顾了一个完成的示例控制台程序,并学习了如何使用 IndexJob 将索引从任何文件夹构建到任何其他文件夹。我们将完成的产品部署到 Amazon EC2 实例,使用命令行上的 dotnet 运行程序,并看到了索引构建到我们指定的索引文件夹中。最后,我们对索引进行了简单的搜索。

本文附带的示例源自 dtSearch 安装文件夹\Program Files (x86)\dtSearch Developer\examples\NetStd\ConsoleDemo中的演示应用程序。浏览 Program Files(x86)\dtSearch Developer\examples\文件夹,可以找到许多使用 dtSearch 引擎的示例程序。

更多关于 dtSearch
dtSearch.com
口袋里的搜索引擎 – 介绍 Android 上的 dtSearch
云端疾速源代码搜索
使用 Azure 文件、RemoteApp 和 dtSearch,从任何计算机或设备跨越 PB 级数据的各种数据类型进行安全即时搜索
使用 dtSearch 引擎进行 Windows Azure SQL 数据库开发
使用 dtSearch 进行分面搜索 - 不是普通的搜索过滤器
使用 dtSearch® ASP.NET Core WebDemo 示例应用程序极速提升您的搜索体验
在您的 Windows 10 通用 (UWP) 应用程序中嵌入搜索引擎
使用 dtSearch Engine DataSource API 索引 SharePoint 网站集
使用 dtSearch® ASP.NET Core WebDemo 示例应用程序
在 AWS 上使用 dtSearch(EC2 & EBS)
使用 dtSearch 和 AWS Aurora 进行全文搜索

© . All rights reserved.