分析

分析是将文本(如任何电子邮件的正文)转换为添加到反向索引中进行搜索的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. iOS开源项目:AFNetworking----写得非常好

    https://github.com/AFNetworking/AFNetworking 与asi-http-request功能类似的网络库,不过是基于NSURLConnection 和 NSOper ...

  2. 05-SSH综合案例:环境搭建之配置文件的引入

    1.3 第三步导入相应配置文件 Struts框架中: * web.xml * 核心过滤器: <filter> <filter-name>struts2</filter-n ...

  3. ArcEngine调用FeatureToLine工具传参问题

    FeatureToLine工具的in_features参数不能为内存图层,否则会报内存错误,正确的写法如下: FeatureToLine ftrToLine = new FeatureToLine() ...

  4. METAL渲染是什么?

    METAL渲染是什么? Metal渲染是由苹果公司为iOS8以及更新版本开发的全新的底层渲染API.它侧重于减少GPU驱动的工作量,从而当Metal调用时,CPU的消耗将降至最低.这样一来,游戏就可以 ...

  5. N 秒打开一个新窗口

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  6. 集群监控之 —— ipmi操作指南

    http://blog.csdn.net/yunsongice/article/details/5408802 智能平台管理界面(IPMI,Intelligent Platform Managemen ...

  7. vbs执行系统命令

    首先说明一下,我的所有代码都是vbscript,jscript我没有研究过,不过我想也差不多. 关于最基础的语法比如变量的申明,分支,循环,函数的调用,等等这些我就不讲了,不懂得自己看一下. 1.我们 ...

  8. 从上往下打印二叉树(java)

    import java.util.ArrayList; import java.util.*; /** public class TreeNode { int val = 0; TreeNode le ...

  9. Hadoop中Writable类之三

    1.BytesWritable <1>定义 ByteWritable是对二进制数据组的封装.它的序列化格式为一个用于指定后面数据字节数的整数域(4个字节),后跟字节本身. 举个例子,假如有 ...

  10. 使用Git 管理heroku的项目(windows)

    此过程与管理github中的项目类似,即是普通的git配置 安装 Heroku Toolbelt, 里面包含了 msygit Foreman,以及heroku的命令行界面 1.首先在heroku上新建 ...