分析

分析是将文本(如任何电子邮件的正文)转换为添加到反向索引中进行搜索的tokens
或terms
的过程。 分析由analyzer
执行,分析器可以是内置分析器或每个索引定义的定制分析器。

书写分析器
测试分析器
书写分析器

有时候,您可以通过配置Elasticsearch内置分析器的工作原理,或将分析组件结合在一起来构建定制分析器,以定制方式分析文本。

分析链

分析器由三个组件构成:

0个或更多字符过滤器
正好是1个tokenizer分词
0或更多Token过滤器
在字段映射上指定分析器

当在类型上创建新字段时,通常在索引创建时创建类型映射时,还可以在使用Put Mapping API添加新字段时,在text
数据类型字段映射上指定分析器。

重要

虽然您可以向索引添加新类型,或向类型添加新字段,但是您不能添加新的分析器或对现有字段进行更改。 如果您这样做,已经编入索引的数据将不正确,您的搜索将无法正常工作。

当您需要更改现有的字段时,应该使用Reindex API重新建立数据

以下是一个简单的示例,指定Elasticsearch中的name
字段映射到项目类型上的Name
POCO属性,在索引时使用whitespace

var createIndexResponse = client.CreateIndex("my-index", c => c
.Mappings(m => m
.Map<Project>(mm => mm
.Properties(p => p
.Text(t => t
.Name(n => n.Name)
.Analyzer("whitespace")
)
)
)
)
);
配置内置分析器

可以配置几个内置的分析器来改变其行为。 例如,standard
分析器可以配置为支持具有包含停止词令牌过滤器的停止词列表。

配置内置分析器需要基于内置分析器创建一个分析器

var createIndexResponse = client.CreateIndex("my-index", c => c
.Settings(s => s
.Analysis(a => a
.Analyzers(aa => aa
.Standard("standard_english", sa => sa
.StopWords("_english_") 
)
)
)
)
.Mappings(m => m
.Map<Project>(mm => mm
.Properties(p => p
.Text(t => t
.Name(n => n.Name)
.Analyzer("standard_english") 
)
)
)
)
);

Elasticsearch中的英文词汇预定义列表

使用配置的standard_english
分析器

{
"settings": {
"analysis": {
"analyzer": {
"standard_english": {
"type": "standard",
"stopwords": [
"_english_"
]
}
}
}
},
"mappings": {
"project": {
"properties": {
"name": {
"type": "text",
"analyzer": "standard_english"
}
}
}
}
}
创建自定义分析器

当内置分析仪不符合您的需求时,可以组合定制分析器。 自定义分析器是从您在分析链中看到的组件和位置增量间隙构建的,该位置增量间距决定了Elasticsearch 应该在数组元素之间插入的间距大小,当字段可以保存多个值时,例如List<string>
POCO属性。

对于这个例子,假设我们正索引编程问题的,问题内容是HTML和源代码

public class Question
{
public int Id { get; set; }
public DateTimeOffset CreationDate { get; set; }
public int Score { get; set; }
public string Body { get; set; }
}

基于我们对编程语言的领域知识,我们希望能够搜索包含“C#”的问题,但是使用standard
分析器“C#”将被分析并产生分词“c”。 这对于我们的用例来说是不行的,因为没有办法将有关“C#”的问题与另一种流行的编程语言“C”的问题区分开来。

我们可以使用自定义分析器解决我们的问题

var createIndexResponse = client.CreateIndex("questions", c => c
.Settings(s => s
.Analysis(a => a
.CharFilters(cf => cf
.Mapping("programming_language", mca => mca
.Mappings(new []
{
"c# => csharp",
"C# => Csharp"
})
)
)
.Analyzers(an => an
.Custom("question", ca => ca
.CharFilters("html_strip", "programming_language")
.Tokenizer("standard")
.Filters("standard", "lowercase", "stop")
)
)
)
)
.Mappings(m => m
.Map<Question>(mm => mm
.AutoMap()
.Properties(p => p
.Text(t => t
.Name(n => n.Body)
.Analyzer("question")
)
)
)
)
);

我们的自定义question
分析器将对问题体进行以下分析

剥离HTML标签
将`C#`和`c#`分别映射到`"CSharp"`和`"csharp"`(所以#不会被tokenizer剥离)
tokenize使用标准的分词器
使用标准分词过滤器过滤分词
小写分词
删除停止分词

全文查询还将在搜索时间对问题主体的查询输入应用相同的分析,这意味着当有人搜索包含输入"C#"
时,它也将被分析并产生分词“csharp”,匹配问题体包含"C#"
(以及“csharp”和case不变量),因为应用的搜索时间分析与索引时间分析相同。

索引和搜索时间分析

使用前面的例子,我们可能不想将相同的分析应用于针对问题体的全文查询的查询输入;我们知道查询输入不会包含HTML标签,因此我们希望在搜索时间应用不同的分析。

除了要在查询时使用的分析器之外,还可以在创建搜索时使用的字段映射时指定分析器

var createIndexResponse = client.CreateIndex("questions", c => c
.Settings(s => s
.Analysis(a => a
.CharFilters(cf => cf
.Mapping("programming_language", mca => mca
.Mappings(new[]
{
"c# => csharp",
"C# => Csharp"
})
)
)
.Analyzers(an => an
.Custom("index_question", ca => ca 
.CharFilters("html_strip", "programming_language")
.Tokenizer("standard")
.Filters("standard", "lowercase", "stop")
)
.Custom("search_question", ca => ca 
.CharFilters("programming_language")
.Tokenizer("standard")
.Filters("standard", "lowercase", "stop")
)
)
)
)
.Mappings(m => m
.Map<Question>(mm => mm
.AutoMap()
.Properties(p => p
.Text(t => t
.Name(n => n.Body)
.Analyzer("index_question")
.SearchAnalyzer("search_question")
)
)
)
)
);

这样就可以在索引时用index_question
分析器分析一个问题体的文本,并且使用不带html_strip
字符过滤器的search_question
分析器来分析问题体字段上的全文查询的输入。

也可以为每个查询指定搜索分析器,即对于来自映射中指定的请求的特定请求使用不同的分析器。 这可以在迭代和改进搜索策略时有用。

测试分析器

在建立自己的分析器时,测试分析器可以达到预期的效果

测试内置分析器

要开始使用Analyze API,我们可以测试一下内置分析器如何分析一段文本

var analyzeResponse = client.Analyze(a => a
.Analyzer("standard") 
.Text("F# is THE SUPERIOR language :)")
);

这将从Elasticsearch返回以下响应

{
"tokens": [
{
"token": "f",
"start_offset": 0,
"end_offset": 1,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "is",
"start_offset": 3,
"end_offset": 5,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "the",
"start_offset": 6,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "superior",
"start_offset": 10,
"end_offset": 18,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "language",
"start_offset": 19,
"end_offset": 27,
"type": "<ALPHANUM>",
"position": 4
}
]
}

这被反序列化为NEST的IAnalyzeResponse
的一个实例,我们可以使用它

foreach (var analyzeToken in analyzeResponse.Tokens)
{
Console.WriteLine($"{analyzeToken.Token}");
}

在我们的文本测试standard
分析器时,我们注意到了

F#被分词为"f"
停止分词"is"和"the"包括在内
"superior"包括在内,但我们也希望将"great"作为superior的同义词

我们将看看我们如何测试内置分析组件的组合,然后构建分析器以满足我们的需求。

测试内置分析组件

临时的分析器可以由内置的分析组件组成,用于测试分析配置

var analyzeResponse = client.Analyze(a => a
.Tokenizer("standard")
.Filter("lowercase", "stop")
.Text("F# is THE SUPERIOR language :)")
);
{
"tokens": [
{
"token": "f",
"start_offset": 0,
"end_offset": 1,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "superior",
"start_offset": 10,
"end_offset": 18,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "language",
"start_offset": 19,
"end_offset": 27,
"type": "<ALPHANUM>",
"position": 4
}
]
}

很好! 这已经删除了停止的单词,但是我们仍然将F#
分词为"f"
,而没有"superior"
的"great"
同义词。

重要

我们来构建一个带有附加组件的自定义分析器来解决这个问题。

在索引中测试自定义分析器

可以在索引中创建自定义分析器,无论是创建索引还是通过更新现有索引上的设置。

添加到现有索引时,首先要关闭它。

在这个例子中,我们将添加一个自定义分析器到一个现有的索引。 首先,我们需要关闭索引

client.CloseIndex("analysis-index");

现在,我们可以更新设置以添加分析器

client.UpdateIndexSettings("analysis-index", i => i
.IndexSettings(s => s
.Analysis(a => a
.CharFilters(cf => cf
.Mapping("my_char_filter", m => m
.Mappings("F# => FSharp")
)
)
.TokenFilters(tf => tf
.Synonym("my_synonym", sf => sf
.Synonyms("superior, great")
)
)
.Analyzers(an => an
.Custom("my_analyzer", ca => ca
.Tokenizer("standard")
.CharFilters("my_char_filter")
.Filters("lowercase", "stop", "my_synonym")
)
)
)
)
);

并再次打开索引。我们还要等待五秒钟,使索引的状态变为绿色

client.OpenIndex("analysis-index");
client.ClusterHealth(h => h
.WaitForStatus(WaitForStatus.Green)
.Index("analysis-index")
.Timeout(TimeSpan.FromSeconds(5))
);

索引打开并准备就绪,我们来测试分析器

{
"tokens": [
{
"token": "fsharp",
"start_offset": 0,
"end_offset": 2,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "superior",
"start_offset": 10,
"end_offset": 18,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "great",
"start_offset": 10,
"end_offset": 18,
"type": "SYNONYM",
"position": 3
},
{
"token": "language",
"start_offset": 19,
"end_offset": 27,
"type": "<ALPHANUM>",
"position": 4
}
]
}
在字段上测试分析器

也可以测试分析器的给定字段类型映射。 给定使用以下设置和映射创建的索引

client.CreateIndex("project-index", i => i
.Settings(s => s
.Analysis(a => a
.CharFilters(cf => cf
.Mapping("my_char_filter", m => m
.Mappings("F# => FSharp")
)
)
.TokenFilters(tf => tf
.Synonym("my_synonym", sf => sf
.Synonyms("superior, great")
)
)
.Analyzers(an => an
.Custom("my_analyzer", ca => ca
.Tokenizer("standard")
.CharFilters("my_char_filter")
.Filters("lowercase", "stop", "my_synonym")
)
)
)
)
.Mappings(m => m
.Map<Project>(mm => mm
.Properties(p => p
.Text(t => t
.Name(n => n.Name)
.Analyzer("my_analyzer")
)
)
)
)
);

name
字段上的分析器可以用

var analyzeResponse = client.Analyze(a => a
.Index("project-index")
.Field<Project>(f => f.Name)
.Text("F# is THE SUPERIOR language :)")
);
具有说明的高级细节

通过在请求中设置Explain()
可以获得有关分析器ss的更多高级细节。

对于这个例子,我们将使用Object Initializer语法而不是Fluent API; 选择对你最适合的!

var analyzeRequest = new AnalyzeRequest
{
Analyzer = "standard",
Text = new [] { "F# is THE SUPERIOR language :)" },
Explain = true
};
var analyzeResponse = client.Analyze(analyzeRequest);

我们现在在响应中获得更多的细节

{
"detail": {
"custom_analyzer": false,
"analyzer": {
"name": "standard",
"tokens": [
{
"token": "f",
"start_offset": 0,
"end_offset": 1,
"type": "<ALPHANUM>",
"position": 0,
"bytes": "[66]",
"positionLength": 1
},
{
"token": "is",
"start_offset": 3,
"end_offset": 5,
"type": "<ALPHANUM>",
"position": 1,
"bytes": "[69 73]",
"positionLength": 1
},
{
"token": "the",
"start_offset": 6,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 2,
"bytes": "[74 68 65]",
"positionLength": 1
},
{
"token": "superior",
"start_offset": 10,
"end_offset": 18,
"type": "<ALPHANUM>",
"position": 3,
"bytes": "[73 75 70 65 72 69 6f 72]",
"positionLength": 1
},
{
"token": "language",
"start_offset": 19,
"end_offset": 27,
"type": "<ALPHANUM>",
"position": 4,
"bytes": "[6c 61 6e 67 75 61 67 65]",
"positionLength": 1
}
]
}
}
}

 
 

Elasticsearch(八)【NEST高级客户端--分析器】的更多相关文章

  1. Elasticsearch(八)【NEST高级客户端--Mapping映射】

    要使用NEST与Elasticsearch进行交互,我们需要能够将我们的解决方案中的POCO类型映射到存储在Elasticsearch中的反向索引中的JSON文档和字段.本节介绍NEST中可用的所有不 ...

  2. Elasticsearch Java高级客户端

    1.  概述 Java REST Client 有两种风格: Java Low Level REST Client :用于Elasticsearch的官方低级客户端.它允许通过http与Elastic ...

  3. 使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索

    使用Elasticsearch 与 NEST 库 构建 .NET 企业级搜索 2015-03-26 dotNET跨平台 最近几年出现的云计算为组织和用户带来了福音.组织对客户的了解达到前所未有的透彻, ...

  4. Elasticsearch系列(五)----JAVA客户端之TransportClient操作详解

    Elasticsearch JAVA操作有三种客户端: 1.TransportClient 2.JestClient 3.RestClient 还有种是2.3中有的NodeClient,在5.5.1中 ...

  5. 【Elasticsearch】.NetCore中Elasticsearch组件NEST的使用

    .NetCore中Elasticsearch组件NEST的使用 1. 安装Docker # 安装Docker curl -fsSL https://get.docker.com | bash -s d ...

  6. NEST - Elasticsearch 的高级客户端

    NEST - High level client Version:5.x 英文原文地址:NEST - High level client 个人建议:学习 NEST 的官方文档时,按照顺序进行,不宜跳来 ...

  7. ElasticSearch.net NEST批量创建修改删除索引完整示例

    本示例采用Elasticsearch+Nest 网上查了很多资料,发现用C#调用Elasticsearch搜索引擎的功能代码很分散,功能不完整,多半是非常简单的操作,没有成型的应用示例.比如新增或修改 ...

  8. ELK 之二:ElasticSearch 和Logstash高级使用

    一:文档 官方文档地址:1.x版本和2.x版本 https://www.elastic.co/guide/en/elasticsearch/guide/index.html 硬件要求: 1.内存,官方 ...

  9. ElasticSearch(八)Elasticsearch-head 连接不上Elasticsearch的原因和解决方案

    在上篇博文里ElasticSearch(七) Elasticsearch在Centos下搭建可视化服务中已经访问到了可视化界面.然后兴奋地进行了数据提交测试,提交啊,刷新啊,就是看不到数据变化,仔细一 ...

随机推荐

  1. Python与Go快速排序

    #!/usr/bin/env python # -*- coding: utf-8 -*- # 快速排序 # 时间复杂度 O(n lgn)-- O(n^2) def quick_sort(array) ...

  2. Type Object——类型对象

    clr会为应用程序使用的每个类型创建一个内部数据结构,这种数据结构称为类型对象. 具有泛型类型参数的类型称为开放类型(open type),CLR禁止构造开放类型的任何实例. 代码引用一个泛型类型时, ...

  3. java线程池相关接口Executor和ExecutorService

    在线程池的api中,Executor接口是最上层的接口,内部只有一个方法.如下: public interface Executor { void execute(Runnable command); ...

  4. c++程序的多文件组织

    当程序规模变大后,一个程序用多个文件组织,便于组织生产.这样,不必每次都重复对所有代码进行编译,而只需编译一次即可.把编译后所形成的目标文件保存起来,以后在需要时把它调出来直接与程序的目标文件相连接即 ...

  5. Python编程快速上手(七)Unsplash批量下载器

    首发于个人博客:http://rhinoc.top/post/python_7.html 程序描述 V1.0输入关键字搜索图片,模拟页面下拉获取更多图片,页面加载完成后获取图片链接并下载至指定文件夹. ...

  6. Java核心技术-集合

    在实现方法时,选择不同的数据结构会导致其实现风格以及性能存在着很大的差异,例如: 需要快速地搜索成千上万个有序的数据项吗?需要快速地在有序的序列中插入和删除元素吗?需要建立键与值之间的关联吗? 1 J ...

  7. 在Ubuntu18.04的Docker中安装Oracle镜像及简单使用

    一.软件环境: 1.OS:Ubuntu 18.04 2.已安装了Docker 二.安装Oracle镜像的过程 1.切换到root账号下,如果是普通账号,下面操作指令前面加sudo 2.搜索oracle ...

  8. SVG DOM常用属性和方法介绍(1)

    12.2  SVG DOM常用属性和方法介绍 将以Adobe SVG Viewer提供的属性和方法为准,因为不同解析器对JavaScript以及相关的属性和方法支持的程度不同,有些方法和属性是某个解析 ...

  9. pyspider示例代码三:用PyQuery解析页面数据

    本系列文章主要记录和讲解pyspider的示例代码,希望能抛砖引玉.pyspider示例代码官方网站是http://demo.pyspider.org/.上面的示例代码太多,无从下手.因此本人找出一些 ...

  10. Mybatis之整体描述

    Mybatis在我看来最大的用处就是封装了jdbc,设置参数操作和获取解析结果集.同时控制了数据库链接等操作,大部分采用了反射来映射javabean对象来进行数据库操作. 1.接下来先整体介绍下主要的 ...