本文目录一览:
如何与es交互
如何与es交互取决于你是否使用Java,这里默认我们都是使用Java语言的。es为Java用户提供了两种内置的客户端。
需要说明的是,两个Java客户端都通过9300端口与集群进行交互,使用es自己的传输协议。集群中的节点之间也通过9300端口进行通信。如果此端口未开放,你的节点将不能组成集群。
Java客户端所在的es版本必须与集群中其他的节点一致,否则,它们可能相互无法识别。
如果不是基于客户端的交互,该怎么办呢?es还为我们提供了基于http协议——以json为数据交互格式的restful API。通过9200端口与es进行通信,你甚至可以通过curl命令与es通信。
总结一下就是大概有三种交互方式。两种是客户端(9300),一种是restful接口(9200)。
es向量搜索插件-knn
1. knn向量检索插件
使用过下面两个插件
优点: 相对elastiknn,该插件支持把底层生成hnsw一个结构加载进内存,376w数据,768纬度向量,搜索性能在300-400ms左右
缺点:
1.该插件需要基于nmslib生成一个c的so文件,该文件比较依赖底层操作系统的库,建立项目最好使用docker容器的方式,不然把本地打的so文件,放到其他环境会出现各种bug,比如: [libKNNIndexV1_7_3_6.so_0x6b1da] _GLOBAL_sub_I_distcomp_sparse_scalar_fast.cc+0x2a
2. 该插件对应于es7.7.1的版本存在各种bug,比如打重复分数、使用cosine距离,但是实际算出来是l2距离,因此建议使用最新的版本,目前最新该插件对应的es版本是7.10.2
2.
优点: 这个是完全对接了es和luence语法的,应该java原生应用,这个不需要安装so库,官网直接就有插件,使用起来比较简单
缺点: 性能相对于上面插件有差距,看官网的QPS在400多左右
elasticsearch映射的数据类型有哪些
es支持大多数java里面的数据类型:
(一)核心数据类型:
(1)string: 默认会被分词,一个完整示例如下
"status": {
"type": "string", //字符串类型
"index": "analyzed"//分词,不分词是:not_analyzed ,设置成no,字段将不会被索引
"analyzer":"ik"//指定分词器
"boost":1.23//字段级别的分数加权
"doc_values":false//对not_analyzed字段,默认都是开启,分词字段不能使用,对排序和聚合能提升较大性能,节约内存
"fielddata":{"format":"disabled"}//针对分词字段,参与排序或聚合时能提高性能,不分词字段统一建议使用doc_value
"fields":{"raw":{"type":"string","index":"not_analyzed"}} //可以对一个字段提供多种索引模式,同一个字段的值,一个分词,一个不分词
"ignore_above":100 //超过100个字符的文本,将会被忽略,不被索引
"include_in_all":ture//设置是否此字段包含在_all字段中,默认是true,除非index设置成no选项
"index_options":"docs"//4个可选参数docs(索引文档号) ,freqs(文档号+词频),positions(文档号+词频+位置,通常用来距离查询),offsets(文档号+词频+位置+偏移量,通常被使用在高亮字段)分词字段默认是position,其他的默认是docs
"norms":{"enable":true,"loading":"lazy"}//分词字段默认配置,不分词字段:默认{"enable":false},存储长度因子和索引时boost,建议对需要参与评分字段使用 ,会额外增加内存消耗量
"null_value":"NULL"//设置一些缺失字段的初始化值,只有string可以使用,分词字段的null值也会被分词
"position_increament_gap":0//影响距离查询或近似查询,可以设置在多值字段的数据上火分词字段上,查询时可指定slop间隔,默认值是100
"store":false//是否单独设置此字段的是否存储而从_source字段中分离,默认是false,只能搜索,不能获取值
"search_analyzer":"ik"//设置搜索时的分词器,默认跟ananlyzer是一致的,比如index时用standard+ngram,搜索时用standard用来完成自动提示功能
"similarity":"BM25"//默认是TF/IDF算法,指定一个字段评分策略,仅仅对字符串型和分词类型有效
"term_vector":"no"//默认不存储向量信息,支持参数yes(term存储),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量) 对快速高亮fast vector highlighter能提升性能,但开启又会加大索引体积,不适合大数据量用
}
(2)数字类型主要如下几种:
long:64位存储
integer:32位存储
short:16位存储
byte:8位存储
double:64位双精度存储
float:32位单精度存储
支持参数:
coerce:true/false 如果数据不是干净的,将自动会将字符串转成合适的数字类型,字符串会被强转成数字,浮点型会被转成整形,经纬度会被转换为标准类型
boost:索引时加权因子
doc_value:是否开启doc_value
ignore_malformed:false(错误的数字类型会报异常)true(将会忽略)
include_in_all:是否包含在_all字段中
index:not_analyzed默认不分词
null_value:默认替代的数字值
precision_step:16 额外存储对应的term,用来加快数值类型在执行范围查询时的性能,索引体积相对变大
store:是否存储具体的值
(3)复合类型
数组类型:没有明显的字段类型设置,任何一个字段的值,都可以被添加0个到多个,要求,他们的类型必须一致:
对象类型:存储类似json具有层级的数据
嵌套类型:支持数组类型的对象Aarray[Object],可层层嵌套
(4)地理类型
geo-point类型: 支持经纬度存储和距离范围检索
geo-shape类型:支持任意图形范围的检索,例如矩形和平面多边形
(5)专用类型
ipv4类型:用来存储IP地址,es内部会转换成long存储
completion类型:使用fst有限状态机来提供suggest前缀查询功能
token_count类型:提供token级别的计数功能
mapper-murmur3类型:安装sudo bin/plugin install mapper-size插件,可支持_size统计_source数据的大小
附件类型:需要 开源es插件支持,可存储office,html等类型
(6)多值字段:
一个字段的值,可以通过多种分词器存储,使用fields参数,支持大多数es数据类型
如何开发elasticsearch插件
检索引擎Elasticsearch支持插件模式,有些时候你可能需要安装一些插件,甚至自己开发插件,这里就提供一个开始ES插件开发示例,ES版本为1.5.2。
一、插件类继承自org.elasticsearch.plugins.AbstractPlugin
package org.elasticsearch.plugin.helloworld;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.AbstractPlugin;
import org.elasticsearch.rest.RestModule;
public class HelloWorldPlugin extends AbstractPlugin {
final ESLogger logger = Loggers.getLogger(getClass());
@Override
public String name() {
//插件名称
return "HelloWorld";
}
@Override
public String description() {
//插件描述
return "Hello World Plugin";
}
//处理模块,因为系统中有很多种Module,所以需要对其类型进行判断
@Override
public void processModule(Module module) {
if(module instanceof RestModule) {
((RestModule)module).addRestAction(HelloWorldHandler.class);
}
if(module instanceof HelloModule) {
logger.info("############## process hello module #####################");
}
}
@Override
public CollectionModule modules(Settings settings) {
//创建自己的模块集合
//如果没有自定义模块,则可以返回空
HelloModule helloModule = new HelloModule();
ArrayListModule list = new ArrayList();
list.add(helloModule);
Collections.unmodifiableList(list);
return list;
}
@SuppressWarnings("rawtypes")
@Override
public CollectionClass? extends LifecycleComponent services() {
//创建自己的服务类集合,服务类需要继承自LifecycleComponent,ES会自动创建出服务类实例,并调用其start方法
//如果没有自定义服务类,则可以返回空
CollectionClass? extends LifecycleComponent list = new ArrayList();
list.add(HelloService.class);
return list;
}
}
Module类其实就是定义了依赖注入规则,如果不清楚,可以去查看Google Guice的文档,基本上是一致的。如上例中的HelloModule:
package org.elasticsearch.plugin.helloworld;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Scopes;
public class HelloModule extends AbstractModule {
@Override
protected void configure() {
//将InjectableService接口类型绑定到InjectableServiceImpl实现类
//在需要注入InjectableService的地方,就会使用InjectableServiceImpl实例
bind(InjectableService.class).to(InjectableServiceImpl.class);
//使HelloService为单例状态
bind(HelloService.class).in(Scopes.SINGLETON);
}
}
不同的模块有不同的处理方式,例如例子中对于RestModule,添加了一个Handler:
package org.elasticsearch.plugin.helloworld;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.RestRequest.Method;
import org.elasticsearch.rest.RestResponse;
public class HelloWorldHandler extends BaseRestHandler {
//注入对象
@Inject
protected HelloWorldHandler(Settings settings, RestController controller, Client client) {
super(settings, controller, client);
//将该Handler绑定到某访问路径
controller.registerHandler(Method.GET, "/hello/", this);
controller.registerHandler(Method.GET, "/hello/{name}", this);
}
//处理绑定路径的请求访问
@Override
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
logger.debug("HelloWorldAction.handleRequest called");
final String name = request.hasParam("name") ? request.param("name") : "world";
String content = "{\"success\":true, \"message\":\"hello " +name+ "\"}";
RestResponse response = new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, content);
channel.sendResponse(response);
}
}
最后在类路径根目录下添加一个名为es-plugin.properties属性文件,指定插件实现类:
plugin=org.elasticsearch.plugin.helloworld.HelloWorldPlugin
二、将插件打成jar包后安装
假设ES_HOME代表Elasticsearch安装目录。在ES_HOME/plugins目录下创建一个名为HelloWorld的目录,该目录名称必须与插件名称相同(区分大小写),然后将jar包拷贝至HelloWorld目录,重新启动即可,当你执行:
curl -GET localhost:9200/hello,就会返回相应结果了。
三、为插件添加页面
如果你想为你的插件添加访问页面,则可以在ES_HOME/plugins/HelloWorld目录下创建一个名为"_site"的目录,该目录名称必须为_site,然后将相应的html页面放置进_site目录即可,如果放置了一个名为index.html文件,则可以通过
localhost:9200/_plugin/HelloWorld/index.html进行访问。
由于Elasticsearch提供了js客户端API,所以使用html静态页面与js就可以完成相应的功能了。