分析

分析是将文本(如任何电子邮件的正文)转换为添加到反向索引中进行搜索的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. 录制手机的视频,转换成gif

    Android: 通过adb命令去进行录屏,然后将录制的视频转换成gif图片: 前提:确保电脑上安装了adb,且Android的level高于19. 1.adb shell screenrecord ...

  2. java关于密码的加密解密

    密码的加密方法有多种,常见的为Aes.Md5 Aes加密,可逆. 其中,Md5加密是采用了散列算法,也就是哈希算法,可以进行多次散列加密.Md5加密是不可逆的,无法解密. MD5是不可逆的单向加密方式 ...

  3. mybatis开发Dao的Mapper动态代理方式

    1. 开发规范Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体跟Dao原始方法中接口实现类的方法相 ...

  4. Pwdump v7.1

    提取windows系统密码  和 hash值

  5. [Training Video - 4] [Selenium IDE]

    Selenium IDE Training List

  6. 我读《从Paxos到zookeeper分布式一致性原理与实践》

    从年后拿到这本书开始阅读,到准备系统分析师考试之前,终于读完了一遍,对Zookeeper有了一个全面的认识,整本书从理论到应用再到细节的阐述,内容安排从逻辑性和实用性上都是很优秀的,对全面认识Zook ...

  7. Caffe 议事(一):从零开始搭建 ResNet 之 残差网络结构介绍和数据准备

    声明:Caffe 系列文章是我们实验室 黄佳斌 大神所写的内部学习文档,已经获得他的授权允许. 本参考资料是在 Ubuntu14.04 版本下进行,并且默认 Caffe 所需的环境已经配置好,下面教大 ...

  8. jdbc注册驱动 class.forName()

    从源码 D:\Javasoftware\MySql\mysql\mysql-connector-java-5.1.7\src\com\mysql\jdbc\Driver.java class.forN ...

  9. 视觉SLAM的数学基础 第一篇 3D空间的位置表示

    视觉SLAM中的数学基础 第一篇 3D空间的位置表示 前言 转眼间一个学期又将过去,距离我上次写<一起做RGBD SLAM>已经半年之久.<一起做>系列反响很不错,主要由于它为 ...

  10. 深入浅出谈数据挖掘zz

    编者的话:本文对数据挖掘概念的产生,数据挖掘与常规数据分析的主要区别,所能解决的几大类问题和所应用的领域都有着非常清晰的论述.作者在此篇文章中认为数据挖掘最重要的要素是分析人员的相关业务知识和思维模式 ...