澳门新浦京8455com有限公司欢迎您!

在 Java 应用程序中使用 Elasticsearch

时间:2019-12-29 05:52

如果您使用过 Apache Lucene 或 Apache Solr,就会知道它们的使用体验非常有趣。尤其在您需要扩展基于 Lucene 或 Solr 的解决方案时,您就会了解 Elasticsearch 项目背后的动机。Elasticsearch(构建于 Lucene 之上)在一个容易管理的包中提供了高性能的全文搜索功能,支持开箱即用地集群化扩展。您可以通过标准的 REST API 或从特定于编程语言的客户端库与 Elasticsearch 进行交互。

说明

在明确了ES的基本概念和使用方法后,我们来学习如何使用ES的Java API.

资料

摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢!

本教程将展示 Elasticsearch 的实际工作原理。首先从命令行访问该 REST API 来了解它的基本信息。然后设置一个本地 Elasticsearch 服务器,并从一个简单的 Java 应用程序与它交互。请参见 下载 部分,获取有关的示例代码。

客户端

你可以用Java客户端做很多事情:

  • 执行标准的index,get,delete,update,search等操作。
  • 在正在运行的集群上执行管理任务。

但是,通过官方文档可以得知,现在存在至少三种Java客户端。

  1. Transport Client
  2. Java High Level REST Client
  3. Java Low Level Rest Client

造成这种混乱的原因是:

  • 长久以来,ES并没有官方的Java客户端,并且Java自身是可以简单支持ES的API的,于是就先做成了TransportClient。但是TransportClient的缺点是显而易见的,它没有使用RESTful风格的接口,而是二进制的方式传输数据。

  • 之后ES官方推出了Java Low Level REST Client,它支持RESTful,用起来也不错。但是缺点也很明显,因为TransportClient的使用者把代码迁移到Low Level REST Client的工作量比较大。官方文档专门为迁移代码出了一堆文档来提供参考。

  • 现在ES官方推出Java High Level REST Client,它是基于Java Low Level REST Client的封装,并且API接收参数和返回值和TransportClient是一样的,使得代码迁移变得容易并且支持了RESTful的风格,兼容了这两种客户端的优点。当然缺点是存在的,就是版本的问题。ES的小版本更新非常频繁,在最理想的情况下,客户端的版本要和ES的版本一致(至少主版本号一致),次版本号不一致的话,基本操作也许可以,但是新API就不支持了。

  • 强烈建议ES5及其以后的版本使用Java High Level REST Client。笔者这里使用的是ES5.6.3,下面的文章将基于JDK1.8+Spring Boot+ES5.6.3 Java High Level REST Client+Maven进行示例。

stackoverflow上的问答:
https://stackoverflow.com/questions/47031840/elasticsearchhow-to-choose-java-client/47036028#47036028

详细说明:

https://www.elastic.co/blog/the-elasticsearch-java-high-level-rest-client-is-out

参考资料:

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/5.6/java-rest-high.html

搭建Elasticsearch服务器

 

『 春夏秋冬失去了你,我怎么过一年四季- 民谣歌词 』

前提条件

要理解本教程的所有示例,需要在您的系统上安装 Elasticsearch。下载针对您的平台的 最新 Elastic Search 程序包。将该包解压到一个方便的位置。在 UNIX 或 Linux 上,通过以下命令启动该实例:

/elastic-search-dir/bin/elasticsearch

在 Windows 上,运行

/elastic-search-dir/bin/elasticsearch.bat

在看到日志消息 started 时,该节点已准备好接受请求。

对于 Java 示例,还需要安装 Eclipse 和 Apache Maven。如果您的系统上还没有它们,请下载和安装它们。

您还需要 cURL。在 Microsoft Windows 上,我使用 Git Bash shell 来运行 cURL。

Java High Level REST Client 介绍

Java High Level REST Client 是基于Java Low Level REST Client的,每个方法都可以是同步或者异步的。同步方法返回响应对象,而异步方法名以“async”结尾,并需要传入一个监听参数,来确保提醒是否有错误发生。

Java High Level REST Client需要Java1.8版本和ES。并且ES的版本要和客户端版本一致。和TransportClient接收的参数和返回值是一样的。

以下实践均是基于5.6.3的ES集群和Java High Level REST Client的。

本文提纲

使用 cURL 执行 REST 命令

可以对 Elasticsearch 发出 cURL 请求,这样很容易从命令行 shell 体验该框架。

“Elasticsearch 是无模式的。它可以接受您提供的任何命令,并处理它以供以后查询。”

Elasticsearch 是无模式的,这意味着它可以接受您提供的任何命令,并处理它以供以后查询。Elasticsearch 中的所有内容都被存储为文档,所以您的第一个练习是存储一个包含歌词的文档。首先创建一个索引,它是您的所有文档类型的容器 — 类似于 MySQL 等关系数据库中的数据库。然后,将一个文档插入该索引中,以便可以查询该文档的数据。

Maven 依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>5.6.3</version>
</dependency>

一、什么是 Elasticsearch-analysis-ik

创建一个索引

Elasticsearch 命令的一般格式是:REST VERBHOST:9200/index/doc-type— 其中 REST VERB 是 PUTGET 或 DELETE。(使用 cURL -X 动词前缀来明确指定 HTTP 方法。)

要创建一个索引,可在您的 shell 中运行以下命令:

curl -XPUT "http://localhost:9200/music/"

初始化

        //Low Level Client init
        RestClient lowLevelRestClient = RestClient.builder(
                new HttpHost("localhost", 9200, "http")).build(); 
        //High Level Client init
        RestHighLevelClient client =
                new RestHighLevelClient(lowLevelRestClient);

High Level REST Client的初始化是依赖Low Level客户端的

二、默认配置 IK

模式可选

尽管 Elasticsearch 是无模式的,但它在幕后使用了 Lucene,后者使用了模式。不过 Elasticsearch 为您隐藏了这种复杂性。实际上,您可以将 Elasticsearch 文档类型简单地视为子索引或表名称。但是,如果您愿意,可以指定一个模式,所以您可以将它视为一种模式可选的数据存储。

Index API

类似HTTP请求,Index API包括index request和index response

三、使用 AnalyzeRequestBuilder 获取分词结果

插入一个文档

要在 /music 索引下创建一个类型,可插入一个文档。在第一个示例中,您的文档包含数据(包含一行)“Deck the Halls” 的歌词,这是一首最初由威尔士诗人 John Ceirog Hughes 于 1885 年编写的传统的圣诞歌曲。

要将包含 “Deck the Halls” 的文档插入索引中,可运行以下命令(将该命令和本教程的其他 cURL 命令都键入到一行中):

curl -XPUT "http://localhost:9200/music/songs/1" -d '
{ "name": "Deck the Halls", "year": 1885, "lyrics": "Fa la la la la" }'

前面的命令使用 PUT 动词将一个文档添加到 /songs 文档类型,并为该文档分配 ID 1。URL 路径显示为 index/doctype/ID

Index request的构造

构造一条index request的例子:

IndexRequest request = new IndexRequest(
        "posts", //index name 
        "doc",  // type
        "1");   // doc id
String jsonString = "{" +
        ""user":"kimchy"," +
        ""postDate":"2013-01-30"," +
        ""message":"trying out Elasticsearch"" +
        "}";
request.source(jsonString, XContentType.JSON);

注意到这里是使用的String 类型。
另一种构造的方法:

Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("user", "kimchy");
jsonMap.put("postDate", new Date());
jsonMap.put("message", "trying out Elasticsearch");
IndexRequest indexRequest = new IndexRequest("posts", "doc", "1")
        .source(jsonMap); 
 //Map会自动转成JSON       

除了String和Map ,XContentBuilder 类型也是可以的:

XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
    builder.field("user", "kimchy");
    builder.field("postDate", new Date());
    builder.field("message", "trying out Elasticsearch");
}
builder.endObject();
IndexRequest indexRequest = new IndexRequest("posts", "doc", "1")
        .source(builder);  

更直接一点的,在实例化index request对象时,可以直接给出键值对:

IndexRequest indexRequest = new IndexRequest("posts", "doc", "1")
        .source("user", "kimchy",
                "postDate", new Date(),
                "message", "trying out Elasticsearch"); 

四、小结

查看文档

要查看该文档,可使用简单的 GET 命令:

curl -XGET "http://localhost:9200/music/songs/1"

Elasticsearch 使用您之前 PUT 进索引中的 JSON 内容作为响应:

{"_index":"music","_type":"songs","_id":"1","_version":1,"found":true,"_source":
{ "name": "Deck the Halls", "year": 1885, "lyrics": "Fa la la la la" }}

index response的获取

运行环境:JDK 7 或 8、Maven 3.0+、ElasticSearch 2.3.2、Elasticsearch-analysis-ik 1.9.2

更新文档

如果您认识到日期写错了,并想将它更改为 1886 怎么办?可运行以下命令来更新文档:

curl -XPUT "http://localhost:9200/music/lyrics/1" -d '{ "name": 
"Deck the Halls", "year": 1886, "lyrics": "Fa la la la la" }'

因为此命令使用了相同的唯一 ID 1,所以该文档会被更新。

同步执行

IndexResponse indexResponse = client.index(request);

技术栈:SpringBoot 1.5+、Spring-data-elasticsearch 2.1.0

删除文档(但暂时不要删除)

暂时不要删除该文档,知道如何删除它就行了:

curl -XDELETE "http://localhost:9200/music/lyrics/1"

异步执行

client.indexAsync(request, new ActionListener<IndexResponse>() {
    @Override
    public void onResponse(IndexResponse indexResponse) {

    }

    @Override
    public void onFailure(Exception e) {

    }
});

需要注意的是,异步执行的方法名以Async结尾,并且多了一个Listener参数,并且需要重写回调方法。
在kibana控制台查询得到数据:

{
  "_index": "posts",
  "_type": "doc",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "user": "kimchy",
    "postDate": "2017-11-01T05:48:26.648Z",
    "message": "trying out Elasticsearch"
  }
}

index request中的数据已经成功入库。

前言

在 Elasticsearch 和插件 elasticsearch-head 安装详解 Elasticsearch 5.3.x。这里我改成了 ElasticSearch 2.3.2。是因为版本对应关系

Spring Boot Version Spring Data Elasticsearch Version Elasticsearch Version

x <= 1.3.5 y <= 1.3.4 z <= 1.7.2*

x >= 1.4.x 2.0.0 <=y < 5.0.0** 2.0.0 <= z < 5.0.0**

* - 只需要你修改下对应的 pom 文件版本号

** - 下一个 ES 的版本会有重大的更新

这里可以看出,5.3.x 不在第二行范围内。因此这里我讲下,如何在 ElasticSearch 2.3.2 中默认配置 IK。

从文件插入文档

这是另一个技巧。您可以使用一个文件的内容来从命令行插入文档。尝试此方法,添加另一首针对传统歌曲 “Ballad of Casey Jones” 的文档。将清单 1 复制到一个名为 caseyjones.json 的文件中;也可以使用示例代码包中的 caseyjones.json 文件(参见 下载)。将该文件放在任何方便对它运行 cURL 命令的地方。(在下载的代码中,该文件位于根目录中。)

index response的返回值操作

client.index()方法返回值类型为IndexResponse,我们可以用它来进行如下操作:

String index = indexResponse.getIndex();  //index名称,类型等信息
String type = indexResponse.getType(); 
String id = indexResponse.getId();
long version = indexResponse.getVersion();
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {

} else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {

}
ShardInfo shardInfo = indexResponse.getShardInfo();
//对分片使用的判断
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {

}
if (shardInfo.getFailed() > 0) {
    for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
        String reason = failure.reason(); 
    }
}

对version冲突的判断:

IndexRequest request = new IndexRequest("posts", "doc", "1")
        .source("field", "value")
        .version(1);
try {
    IndexResponse response = client.index(request);
} catch(ElasticsearchException e) {
    if (e.status() == RestStatus.CONFLICT) {

    }
}

对index动作的判断:

IndexRequest request = new IndexRequest("posts", "doc", "1")
        .source("field", "value")
        .opType(DocWriteRequest.OpType.CREATE);//create or update
try {
    IndexResponse response = client.index(request);
} catch(ElasticsearchException e) {
    if (e.status() == RestStatus.CONFLICT) {

    }
}

一、什么是 Elasticsearch-analysis-ik

了解什么是 Elasticsearch-analysis-ik,首先了解什么是 IK Analyzer。 IK Analyzer 是基于 lucene 实现的分词开源框架。官方地址:

Elasticsearch-analysis-ik 则是将 IK Analyzer 集成 Elasticsearch 的插件,并支持自定义词典。GitHub 地址:

分析器 Analyzer: ik_smart 或 ik_max_word

分词器 Tokenizer: ik_smart 或 ik_max_word

清单 1. “Ballad of Casey Jones” 的 JSON 文档
{
  "artist": "Wallace Saunders",
  "year": 1909,
  "styles": ["traditional"],
  "album": "Unknown",
  "name": "Ballad of Casey Jones",
  "lyrics": "Come all you rounders if you want to hear
The story of a brave engineer
Casey Jones was the rounder's name....
Come all you rounders if you want to hear
The story of a brave engineer
Casey Jones was the rounder's name
On the six-eight wheeler, boys, he won his fame
The caller called Casey at half past four
He kissed his wife at the station door
He mounted to the cabin with the orders in his hand
And he took his farewell trip to that promis'd land

Chorus:
Casey Jones--mounted to his cabin
Casey Jones--with his orders in his hand
Casey Jones--mounted to his cabin
And he took his... land"
}

运行以下命令,将此文档 PUT 到您的 music 索引中:

$ curl -XPUT "http://localhost:9200/music/lyrics/2" -d @caseyjones.json

在该索引中时,将清单 2 的内容(包含另一手民歌 “Walking Boss”)保存到 walking.json 文件中。

GET API

二、默认配置 IK

在 Elasticsearch-analysis-ik 官网中可以看到,其中版本需要对应:

IK版 ES版本

主 5.x -> master

5.3.2 5.3.2

5.2.2 5.2.2

5.1.2 5.1.2

1.10.1 2.4.1

1.9.5 2.3.5

1.8.1 2.2.1

1.7.0 2.1.1

1.5.0 2.0.0

1.2.6 1.0.0

1.2.5 0.90.x

1.1.3 0.20.x

1.0.0 0.16.2 -> 0.19.0

这里使用的是 Elasticsearch-analysis-ik 1.9.2,支持 ElasticSearch 2.3.2。下载地址:

解压 zip 文件,复制里面的内容到 elasticsearch-2.3.2/plugins/ik。

cd elasticsearch-2.3.2/plugins

mkdir ik

cp ...

在 elasticsearch-2.3.2/config/elasticsearch.yml 增加配置:

index.analysis.analyzer.default.tokenizer : "ik_max_word"

index.analysis.analyzer.default.type: "ik"

配置默认分词器为 ik,并指定分词器为 ik_max_word。

然后重启 ES 即可。验证 IK 是否成功安装,访问下

localhost:9200/_analyze?analyzer=ik&pretty=true&text=泥瓦匠的博客是bysocket.com

可以得到下面的结果集:

{

"tokens": [

{

"token": "泥瓦匠",

"start_offset": 0,

"end_offset": 3,

"type": "CN_WORD",

"position": 0

},

{

"token": "泥",

"start_offset": 0,

"end_offset": 1,

"type": "CN_WORD",

"position": 1

},

{

"token": "瓦匠",

"start_offset": 1,

"end_offset": 3,

"type": "CN_WORD",

"position": 2

},

8455新葡萄娱乐,{

"token": "匠",

"start_offset": 2,

"end_offset": 3,

"type": "CN_WORD",

"position": 3

},

{

"token": "博客",

"start_offset": 4,

"end_offset": 6,

"type": "CN_WORD",

"position": 4

},

{

"token": "bysocket.com",

"start_offset": 8,

"end_offset": 20,

"type": "LETTER",

"position": 5

},

{

"token": "bysocket",

"start_offset": 8,

"end_offset": 16,

"type": "ENGLISH",

"position": 6

},

{

"token": "com",

"start_offset": 17,

"end_offset": 20,

"type": "ENGLISH",

"position": 7

}

]

}

记得在Docker 容器安装时,需要对应的端口开发。

清单 2. “Walking Boss” JSON
{
  "artist": "Clarence Ashley",
  "year": 1920
  "name": "Walking Boss",
  "styles": ["folk","protest"],
  "album": "Traditional",
  "lyrics": "Walkin' boss
Walkin' boss
Walkin' boss
I don't belong to you

I belong
I belong
I belong
To that steel driving crew

Well you work one day
Work one day
Work one day
Then go lay around the shanty two"
}

将此文档推送到索引中:

$ curl -XPUT "http://localhost:9200/music/lyrics/3" -d @walking.json

GET request

GetRequest getRequest = new GetRequest(
        "posts",//index name 
        "doc",  //type
        "1");   //id

三、使用 AnalyzeRequestBuilder 获取分词结果

ES 中默认配置 IK 后,通过 Rest HTTP 的方式我们可以进行得到分词结果。那么在 Spring Boot 和提供的客户端依赖 spring-data-elasticsearch 中如何获取到分词结果。

加入依赖 pom.xml

org.springframework.boot

spring-boot-starter-data-elasticsearch

在 application.properties 配置 ES 的地址:

# ES

spring.data.elasticsearch.repositories.enabled = true

spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300

然后创建一个方法,入参是搜索词,返回的是分词结果列表。

@Autowired

private ElasticsearchTemplate elasticsearchTemplate;

/**

* 调用 ES 获取 IK 分词后结果

*

* @param searchContent

* @return

*/

private List getIkAnalyzeSearchTerms(String searchContent) {

// 调用 IK 分词分词

AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(),

AnalyzeAction.INSTANCE,"indexName",searchContent);

ikRequest.setTokenizer;

List ikTokenList = ikRequest.execute().actionGet().getTokens();

// 循环赋值

List searchTermList = new ArrayList<>();

ikTokenList.forEach(ikToken -> { searchTermList.add(ikToken.getTerm;

return searchTermList;

}

indexName 这里是指在 ES 设置的索引名称。

从容器注入的 ElasticsearchTemplate Bean 中获取 Client ,再通过 AnalyzeRequestBuilder 分析请求类型中进行分词并获取分词结果 AnalyzeResponse.AnalyzeToken 列表。