说说本地搜寻

在远古时代,我在一家公司中担任IT专家,有时会出现搜索本地文档存储的任务。期望不仅通过文件名搜索,而且还通过内容搜索。当时,诸如档案管理员之类的本地搜索机制仍然很流行,甚至还有与Yandex分离的搜索引擎。但是这些不是企业解决方案;它们不能集中部署以进行共享。为了诚实起见,Yandex开始做类似的事情,但后来放弃了。



但是所有这些解决方案都没有我需要的东西:



  • 集中安装
  • 考虑到访问权限的搜索结果
  • 按文件内容搜寻
  • 形态学


我决定自己做。



为了避免解释和误解的差异,我将逐点披露自己的形式。

集中安装-客户端-服务器执行。上述所有解决方案都存在一个基本问题-每个用户都创建自己的本地搜索索引,如果存储量大,索引编制延迟,则计算机上的用户配置文件会增加,并且在新员工到达或搬到新计算机的情况下通常不方便。



考虑到权利的搜索结果-此处的一切都很简单-结果必须与员工对文件资源的权利相对应。否则,事实证明,即使该雇员没有该资源的权限,他也可以从搜索缓存中读取所有内容。结果会很尴尬,同意吗?按文档的内容进行搜索-按文档的文本进行搜索,在我看来,这里的一切都很明显,并且没有任何差异。



形态甚至更简单。在查询“刀”中指定,并同时接收“刀”和“刀”,“刀”和“刀”。为此,最好使用俄语和英语。

我们已经决定问题的解决方案,我们可以继续执行。



作为搜索引擎,我选择了Sphinx系统,界面开发语言是C#和.net,结果该项目以法国侦探的名字命名为Vidocq(Vidocq)。嗯,就像,它找到了所有东西,仅此而已。



从结构上讲,该应用程序如下所示:



搜索机器人以给定的扩展名列表递归地爬行文件资源并处理文件。处理包括检索文件的内容,压缩文本-从文本中删除引号,逗号,多余的空格等,然后将内容放置在数据库(MS SQL)中,标记放置日期,然后机器人继续前进。



Sphins索引器直接与接收到的库一起使用,形成自己的索引,并返回指向找到的文件的指针和找到的文本片段的片段作为响应。



用C#开发了一种表单,该表单通过MySQL连接器与Sphinx进行了通信。Sphinx根据请求提供文件数组,然后针对搜索用户的访问权限对数组进行过滤,将输出格式化并显示给用户。



我们需要存储有关文件的以下信息:



  • 档案编号
  • 文件名
  • 文件的路径
  • 文件内容
  • 扩张
  • 日期已添加到基准


这一切都在一个表中完成,搜索机器人将向其中添加所有内容。添加日期是必需的,以便下一轮机械手将文件修改的日期与它在数据库中放置的日期进行比较,如果日期不同,则更新有关文件的信息。



然后设置搜索引擎本身。我不会描述整个配置,它将在项目档案中提供,但是我仅介绍要点。



构成



源文档库的主要请求:documents_base



{
	sql_query = \
	select \
	DocumentId as 'Id', \
	DocumentPath as 'Path', \
	DocumentTitle as 'Title', \
	DocumentExtention as 'Extension', \
	DocumentContent as 'Content' \
	from \
	VidocqDocs
}


通过lemmatizer设置形态。



index documents
{
	source 			= documents
	path 			= D:/work/VidocqSearcher/Sphinx/data/index
    morphology 		= lemmatize_ru_all, lemmatize_en_all
}


之后,您可以在基础上设置索引器并检查工作。



d:\work\VidocqSearcher\Sphinx\bin\indexer.exe documents --config D:\work\VidocqSearcher\Sphinx\bin\main.conf –rotate


在这里,指向索引器的路径后面是要放置已处理索引的索引的名称,配置的路径和–rotate标志意味着将动态执行索引,即搜索服务正在运行。索引编制完成后,索引将替换为更新的索引。



我们在控制台中检查工作。作为接口,您可以使用MySQL客户端,例如从Web服务器工具包中获取的客户端。



mysql -h 127.0.0.1 -P 9306


在该请求之后,请从文档中选择ID;如果您当然启动了Sphinx服务本身并正确执行了所有操作,则应该返回索引文档列表。

好的,控制台很棒,但是我们不会强迫用户键入命令,对吗?



我绘制了一个这样的表格,







然后在其中显示搜索结果







。单击特定结果时,将打开一个文档。



如何执行。



using MySql.Data.MySqlClient;
string connectionString = "Server=127.0.0.1;Port=9306";
            var query = "select id, title, extension, path, snippet(content, '" + textBoxSearch.Text.Trim() + "', 'query_mode=1') as snippet from documents " +
                "where ";
            if (checkBoxTitle.IsChecked == true && checkBoxContent.IsChecked == true)
            {
                query += "match ('@(title,content)" + textBoxSearch.Text.Trim() + "')";
            }
            
            if (checkBoxTitle.IsChecked == false && checkBoxContent.IsChecked == true)
            {
                query += "match ('@content" + textBoxSearch.Text.Trim() + "')";
            }
            
            if (checkBoxTitle.IsChecked == true && checkBoxContent.IsChecked == false)
            {
                query += "match ('@title" + textBoxSearch.Text.Trim() + "')";
            }
            
            

            if (checkBoxWord.IsChecked == true && checkBoxText.IsChecked == true)
            {
                query += "and extension in ('.docx', '.doc', '.txt');";
            }
            if (checkBoxWord.IsChecked == true && checkBoxText.IsChecked == false)
            {
                query += "and extension in ('.docx', '.doc');";
            }

            if (checkBoxWord.IsChecked == false && checkBoxText.IsChecked == true)
            {
                query += "and extension in ('.txt');";
            }


是的,有一个bydloc代码,但这是一个MVP。



实际上,根据设置的复选框,此处形成了对狮身人面像的请求。复选框指示要在其中搜索的文件类型以及搜索区域。



然后,请求转到Sphinx,然后解析结果。



using (var command = new MySqlCommand(query, connection))
            {
                connection.Open();

                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var id = reader.GetUInt16("id");
                        var title = reader.GetString("title");
                        var path = reader.GetString("path");
                        var extension = reader.GetString("extension");
                        var snippet = reader.GetString("snippet");
                        bool isFileExist = File.Exists(path);
                        if (isFileExist == true)
                        {
                            System.Windows.Controls.RichTextBox textBlock = new RichTextBox();
                            textBlock.IsReadOnly = true;
                            string xName = "id" + id.ToString();
                            textBlock.Name = xName;
                            textBlock.Tag = path;
                            textBlock.GotFocus += new System.Windows.RoutedEventHandler(ShowClickHello);
                            snippet = System.Text.RegularExpressions.Regex.Replace(snippet, "<.*?>", String.Empty);
                            Paragraph paragraph = new Paragraph();
                            paragraph.Inlines.Add(new Bold(new Run(path + "\r\n")));
                            paragraph.Inlines.Add(new Run(snippet));
                            textBlock.Document = new FlowDocument(paragraph);
                            StackPanelResult.Children.Add(textBlock);
                        }
                        else
                        {
                            counteraccess--;
                        }
                    }
                }
            }


在同一阶段,产生了问题。问题的每个元素都是一个RichTextBox,其中包含一个事件,用于在单击时打开文档。将项目放置在StackPanel上,然后再检查用户文件。因此,用户不可访问的文件将不会包含在输出中。

该解决方案的优点:



  • 索引集中发生
  • 根据访问权限准确显示
  • 可按文件类型自定义搜索


当然,为使此类解决方案全面运行,必须在公司中适当地组织文件档案。理想情况下,应配置漫游用户配置文件等。是的,我了解SharePoint,Windows搜索以及最有可能的其他解决方案。然后,您可以无休止地讨论开发平台的选择,搜索引擎Sphinx,Manticore或Elastic等。但是我有兴趣使用我所了解的工具来解决问题。它当前以MVP模式运行,但是我正在开发它。



但是无论如何,我随时准备听听您的建议,这些建议可以改进或重做。



All Articles