telescope-looking-out-on-city

弹性搜索是搜索文本数据常用的解决方案选项。最近,我们用它来在GCP上的一个Web应用程序中构建员工搜索功能。

简而言之,我们希望能够按员工”姓名”的初始几个字符搜索员工。加:

  1. 按经理、城市、国家、子段、细分的顺序显示相关匹配。这是在登录用户的上下文中。
  2. 搜索即用型/自动完成建议器。
  3. 可重用组件。

您可能还喜欢:什么是弹性搜索?(以及为什么你需要使用它).

弹性搜索

弹性搜索使用倒置索引来加快搜索速度。弹性搜索 v7.2.0 软件安装在 Google VM 上。员工数据存储为 JSON 文档,用于索引和搜索目的的弹性搜索。

下图描述了员工搜索的总体解决方案。

Solution for each employee search

首先,您需要创建称为”员工”的索引

PUT employee
{
"settings": {
"index": {
"max_ngram_diff": "20",
"number_of_shards": "5",
"provided_name": "employee",
"analysis": {
"filter": {
"nGram_filter": {
"token_chars": ["letter", "digit", "punctuation", "symbol"],
"min_gram": "2",
"type": "nGram",
"max_gram": "20"
}
},
"normalizer": {
"lowerasciinormalizer": {
"filter": ["lowercase", "asciifolding"],
"type": "custom"
}
}
}
}
}
}

Ngram(令牌)应用作分析器。

规范化器筛选器(如小写回写)有助于区分大小写的搜索,并分别忽略特殊字符/空格。

然后,为需要执行搜索的字段(即员工姓名)创建自定义映射。在”名称”字段上使用”下分规范化”。为 JSON 文档中的其他字段生成默认映射。

PUT /employee/_mapping
{
"properties": {
"name": {
"type": "keyword",
"normalizer": "lowerasciinormalizer"
}
}
}

可以使用”_bulk”API 将员工 JSON 文档导入到弹性搜索中。

PUT /employee/_bulk
{"index":{"_id":"02243876"}}
{"empid":"02243876","name":"Peter Scott","lastname":"Scott","firstname":"Peter","managername":"John England","city":"Chicago","country":"USA","subsegment":"Auditing","segment":"Accounts"}

您还可以使用 Kibana GUI 执行从 CSV 输入文件到弹性搜索的批量数据导入。在批量导入之前,Kibana GUI 将指导您完成索引设置和映射过程。

Google 持久磁盘用作员工 JSON 文档的存储。

“搜索”微服务

这是我们的自定义RESTful 微服务,用于将输入搜索关键字转换为弹性搜索 DSL 查询子句并将结果返回给 Angular 客户端应用程序NET 核心 2.2 框架。

NEST 是 .NET 中的弹性搜索客户端库。我们将安装 NEST 的 Nuget 包,以便从微服务代码中与弹性搜索进行交互。

请参阅使用 Lambda 表达式使用 NEST 库生成搜索查询子句。默认情况下,弹性搜索按相关性分数对匹配的搜索结果进行排序,该分数衡量每个文档与查询匹配的程度。

async Task<IList<Employee>> ReturnElasticSearchResult(Data data) {
  ISearchResponse<Employee> response = null;           
  var elasticSearchUrl = _configuration["elasricsearch:url"];
  var uri = new Uri(elasticSearchUrl);
  var settings = new ConnectionSettings(uri);
  settings.DefaultIndex("employee");                
  ElasticClient client = new ElasticClient(settings);
  Elasticsearch.Net.SearchType searchType = Elasticsearch.Net.SearchType.QueryThenFetch;
  response = client.Search<Employee>(s => s
                .SearchType(searchType)
                .Query(q => (q.Term(t => t.mangername, data.managername) && q.Wildcard(w => w.name, "*" + data.name + "*")) ||
                (q.Term(t2 => t2.city, data.city) && q.Wildcard(w => w.name, "*" + data.name + "*")) ||
                (q.Term(t3 => t3.country, data.country) && q.Wildcard(w => w.name, "*" + data.name + "*")) ||
                (q.Term(t4 => t4.subsegment, data.subsegment) && q.Wildcard(w => w.name, "*" + data.name + "*")) ||
                (q.Term(t5 => t5.segment, data.segment) && q.Wildcard(w => w.name, "*" + data.name + "*")))
                .Sort(sort => sort.Field(f => f.Field("_score").Descending())));
  return response.Documents.ToList();
}

搜索服务将在 API 网关上公开为 API,并由 Angular 应用程序客户端调用。API 网关可用于通过缓存搜索结果来提高搜索性能。

角搜索 GUI 组件

角度搜索组件将在 GUI 中显示用于搜索目的的输入文本框。此组件作为 npm 组件导出和导入,在另一个需要员工搜索的应用程序中。

角自动完成功能应在 UI 上使用,以提示/建议员工匹配搜索关键字。

debounceTime(300)用于在值更改事件之后等待 300 ms 进行下一次弹性搜索 API 调用。请参阅组件.ts 文件中的代码块。

ngOnInit() {
    this.searchEmployeesCtrl.valueChanges.pipe(
        debounceTime(300),
        tap(() => {        
          this.employees = [];
          this.isLoading = true;
        }),

        switchMap(          
          value =>(this.http.post("api/elasticsearch", {'name': value, 
  'managername':this.emp.managername, 
  'city':this.emp.city,                                                                 
  'country':this.emp.country,
                                                  'segment':this.emp.segment,  
  'subsegment':this.emp.subsegment})
          ).pipe(
            finalize(() => {
              this.isLoading = false
            }),
          )
        )
      ).subscribe((data:Employee[]) => {        
          this.employees = data;
        });
  }

请参阅来自组件.html 文件的代码块。

<input matInput placeholder="Employee Search" #Search aria-label="State" [matAutocomplete]="auto" [formControl]="searchEmployeesCtrl">
    <mat-icon matSuffix>search</mat-icon>

    <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" (optionSelected)='getPosts($event.option.value,Search )' >
      <mat-option *ngIf="isLoading" class="is-loading" >Loading...</mat-option>
      <ng-container *ngIf="!isLoading">
        <mat-option *ngFor="let employee of employees" [value]="employee

名称_lt;/span_gt;
</mat 选项>
</ng-容器>
</mat-自动完成>
</mat-form-字段>

相关文章

Comments are closed.