分析

分析是将文本(如任何电子邮件的正文)转换为添加到反向索引中进行搜索的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. 值类型 struct

    由于值类型存在装箱和拆箱的过程,所有导致在修改值类型对象内部数据时,有可能会出现一些与预想不同的结果. 比如 Point p = , ); Console.WriteLine(p); p.Change ...

  2. 79. Word Search (Array; DFS,Back-Track)

    Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from l ...

  3. sqlserver top 赋值

    DECLARE @password2 VARCHAR(30) select top 1 @password2= password from teacher 不要写成 DECLARE @password ...

  4. ubuntu下安装最新的nodejs

    # apt-get update # apt-get install -y python-software-properties software-properties-common # add-ap ...

  5. asp.net网站全局控制文件内注册事件

    在管理ASP.NET网站的时候,有时会对网站整体做出控制,这时把这些代码写在global.asax内可以做到全局控制. 未添加任何代码的global.asax文件如下: <script runa ...

  6. [原创]Cef3 2623.1397 开启ppapi flash插件

    最近发现WKE播放Flash或者游戏时会有很多BUG,例如视频无法播放或者是Stage3D无法使用等问题. 经过研究应该是精简版本导致的,所以决定尝试使用CEF3移植入SOUI,但是DEMO中版本有点 ...

  7. centos7 dubbokeeper安装

    下载dubbokeeper源码 git clone https://github.com/dubboclub/dubbokeeper   mysql 先执行install-mysql.sh   编译好 ...

  8. 04 Python入门学习-流程控制(if else elif while for)

    一:流程控制if 语法一: if 条件: code1 code2 code3 ... age = 20 height = 170 weight = 60 sex = 'female' is_beaut ...

  9. UVa 818Cutting Chains (暴力dfs+位运算+二进制法)

    题意:有 n 个圆环,其中有一些已经扣在一起了,现在要打开尽量少的环,使所有的环可以组成一条链. 析:刚开始看的时候,确实是不会啊....现在有点思路,但是还是差一点,方法也不够好,最后还是参考了网上 ...

  10. python使用git进行版本控制2

    对上一次的readme文件进行修改 现在,运行git status命令看看结果 $ git statusOn branch masterChanges not staged for commit:  ...