ElasticSerach

序言

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要发挥其强大的作用,你需使用Java并要将其集成到你的应用中。Lucene非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。
Elasticsearch也是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。
Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 实时分析的分布式搜索引擎
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

牵连

Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)

同样出名的全文搜索引擎还有solr

索引结构

概念

索引 类似mysql的数据库

类型 类似mysql的表

文档 类似mysql的行

一般我们初学时会把这些与数据库进行对照方便理解

  • Index->Database
  • Type->Table (最新版本已经不使用Type了,所以很多人会奇怪为什么去掉了?ES并非和数据库是相同的,所以不要完全按数据库的方式来看ES)
  • Document->Row

倒排索引

(一般我们从目录找到相应的文章为正向索引,如果从关键词索引找到对应的文章即倒排索引)

索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。

映射与数据类型

 映射(Mapping)相当于数据表的表结构。ElasticSearch中的映射(Mapping)用来 定义一个文档,可以定义所包含的字段以及字段的类型、分词器及属性等等。 

​ 映射可以分为动态映射和静态映射。

​ 动态映射 (dynamic mapping):在关系数据库中,需要事先创建数据库,然后在 该数据库实例下创建数据表,然后才能在该数据表中插入数据。而ElasticSearch中不需 要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类 型,这种机制称之为动态映射。

 静态映射 :在ElasticSearch中也可以事先定义好映射,包含文档的各个字段及其类 型等,这种方式称之为静态映射。 

RESTAPI

插入 post /index/type

POST http://localhost:9200/testindex/doc HTTP/1.1
User-Agent: Fiddler
content-type: application/json
Host: localhost:9200
Content-Length: 39

{
"name":"哈哈哈",
"counts":100
}

查询

GET http://localhost:9200/testindex/doc/_search HTTP/1.1
User-Agent: Fiddler
Host: localhost:9200
Content-Length: 0

分词

POST http://localhost:9200/testindex/_analyze HTTP/1.1
User-Agent: Fiddler
Host: localhost:9200
Content-Length: 50
content-type: application/json

{
"analyzer":"chinese",
"text":"江苏苏州"
}

ik分词器

ik_smart 最少切分

ik_max_word 最细切分(如果切分的词还能继续切分,则继续切分,eg 江苏苏州市, 切分后为 江苏、 苏州市 、苏州、 市)

Kibana

可视化工具

安装:

  • 解压
  • 修改config/kibana.yml配置文件
  • 执行kibana.bat

商品搜索接入es分析

商品搜索列表展示信息

分析需要哪些信息

商品名称即sku名称     text(不可以是keyword,不能分词)
商品id               decimal
商品图片                text
商品价格                 decimal
标签            keyword    
店铺名称         text
店铺id或者店铺超链接   text
商品超链接  text
评论数   integer
优惠信息  text
商品分类   keyword
品牌  keyword
规格  integer

JAVA中的应用

三种Java客户端

  • Transport Client 没有Restful风格,以二进制传输数据 淘汰
  • Java Low Level Rest Client 支持Restful,缺点是从Transport迁移过来的成本很大
  • Java High Level REST Client 基于low level的封装,请求和响应同Transport一致,迁移成本很低

主推Java High Level REST Client

注意

使用通用接收数据类便于进行批量新增。请注意,批量新增索引的大小在 1000-5000条数据为最佳,数据量大小在 5MB-10MB 为最佳;超过可能会影响性能

高级客户端中的接口

查询QueryBuilders

踩坑:使用Term(s)QueryBuilder查询内容需要转换成全小写,而MatchQueryBuilder不需要转换
原因:Term(s)QueryBuilder输入的词条不会经过处理;而MatchQueryBuilder输入的词条
会被es解析并进行分词,在此过程中就已经转换成全小写。(es在存储字段时,已做解析、分词和小写处理。看见的是大写的字段内容,实际在es里已经被当作小写进行处理)

1. 词条查询(Term Query)

TermQueryBuilder

词条查询是ElasticSearch的一个简单查询。它仅匹配在给定字段中含有该词条的文档,而且是确切的、未经分析的词条。term 查询 会查找我们设定的准确值。term 查询本身很简单,它接受一个字段名和我们希望查找的值。

记住,词条查询是未经分析的,因此需要提供跟索引文档中的词条完全匹配的词条。请注意,我们使用小写开头的california来搜索,而不是California,因为California一词在建立索引时已经变成了california(默认分词器)。

2. 多词条查询(Terms Query)

TermsQueryBuilder

词条查询(Term Query)允许匹配单个未经分析的词条,多词条查询(Terms Query)可以用来匹配多个这样的词条。只要指定字段包含任一我们给定的词条,就可以查询到该文档。

3.MatchQueryBuilder

与TermQueryBuilder类似。

3. 范围查询(Range Query)

范围查询使我们能够找到在某一字段值在某个范围里的文档,字段可以是数值型,也可以是基于字符串的。范围查询只能针对单个字段。

方法:

(1)gte() :范围查询将匹配字段值大于或等于此参数值的文档。

(2)gt() :范围查询将匹配字段值大于此参数值的文档。

(3)lte() :范围查询将匹配字段值小于或等于此参数值的文档。

(4)lt() :范围查询将匹配字段值小于此参数值的文档。

(5)from() 开始值 to() 结束值 这两个函数与includeLower()和includeUpper()函数配套使用。

includeLower(true) 表示 from() 查询将匹配字段值大于或等于此参数值的文档;

includeLower(false) 表示 from() 查询将匹配字段值大于此参数值的文档;

includeUpper(true) 表示 to() 查询将匹配字段值小于或等于此参数值的文档;

includeUpper(false) 表示 to() 查询将匹配字段值小于此参数值的文档;

BoolQueryBuilder queryBuilder= QueryBuilders.boolQuery();

// 1,matchAllQuery匹配所有
queryBuilder.matchAllQuery();

// 2,termQuery精准匹配,大小写敏感且不支持
queryBuilder.termQuery("key", value) 一次匹配一个值,完全匹配
queryBuilder.termsQuery("key", obj1, obj2..)   一次匹配多个值

// 3,matchPhraseQuery对中文精确匹配
queryBuilder.matchPhraseQuery("key", value)

// 4,matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
queryBuilder.matchQuery(key, value);

// 5,multiMatchQuery("text", "field1", "field2"..); 匹配多个字段, field有通配符忒行
queryBuilder.multiMatchQuery(value, key1, key2, key3);

// 6,组合查询
   * must:   AND
   * mustNot: NOT
   * should:: OR
     queryBuilder.must(QueryBuilders.termQuery("user", "kimchy"))
           .mustNot(QueryBuilders.termQuery("message", "nihao"))
           .should(QueryBuilders.termQuery("gender", "male"));