Elasticsearch:一切为了搜索
是什么:
一个分布式、RESTful 风格的搜索和数据分析引擎
基于Lucene的搜索服务器。
相似产品:
Apache solr:基于Lucene
基本概念:
全文检索:
在插入数据时,es会根据分词器将数据进行分词,然后对这些分词建立索引,记录出现的次数与位置。
field:字段
document:文档,包含多个field字段。
type:类型。
版本7.x不建议使用(type),8.x将不支持。同一个Index 下不同的 Type 如果有同名的字段,他们会被 Luecence 当作同一个字段 ,并且他们的定义必须相同。
index:索引。名称需要小写
倒排索引:
由文档所有不重复的词组成,记录不同词出现的次数和位置。适用于快速全文检索。
结构:
term:单词。按照分词器规则生成的单词
term index:单词的索引
term dictionary:单词字典。存放term单词
posting list:倒排列表。记录每个单词出现的位置、词频(出现的频率)、偏移量offset等
shard:分片
可以将一个index切分为多个shard,然后将之存储在多台服务器上,以增大一个index的存储的数据量,加速检索能力,提升检索性能。
primary shard(主分片):解决节点容量问题,通过主分片,可以将数据分布到集群内所有节点
一经创建,不可修改
replica:副本
replica与shard数据相同,replica起到备份作用。当shard发生故障时,可以从replica中读取数据,保证系统不受影响
提供搜索功能,通过设置合理的replicas数量可以极高的提高搜索吞吐量
分片设置过小:
1、导致后续无法增加节点进行水平扩展
2、导致分片的数据量太大,数据在重新分配时耗时。
分片设置过大:
1、影响搜索结果的相关性打分,影响统计结果的准确性
2、单个节点上分片过多,浪费资源,影响性能。
node:节点
单个elasticsearch实例。节点名称系统随机分配
cluster:集群
一组 Elasticsearch 实例。默认集群名称为 elasticsearch。
分词:
是将文件转换一系列单词(term)的过程,也称为文本分析。在es中称为analysis
分析器组成部分:
Character Filters:针对原始文本进行处理,比如去除html特殊标记符
Tokenizer:分词器,将原始文本按一定规则切分为单词
lowercase:将所有term转换为小写
stop:删除stop words
NGram和Edge NGram:连词分割
Synonym:添加近义词的term
Token Filters:针对Tokenizer处理后的单词进行加工,例如转小写、删除或新增等
analyze_api:
POST _analyze
{
"analyzer": "standard", 分词器
"text": "hello world!" 测试文本
}
分词器:
es自带分词器:
1、Standard:默认分词器,按词切分,支持多语言
2、Simple:安装非字母切分
3、Whitespace:按空格键切分
4、Stop:相比simple多了stop world处理
5、keyword:不分词,直接当做单词输出
6、Pattern:通过正则表达式自定义分隔符,默认是\w+,即非词的符号作为分隔符
中文分词器:
IK:实现中英文分词,自定义分词库,支持热更新分词词典
jieba:Python中最流行的分词系统,支持分词与词性标注,支持繁体分词,自定义词典,并行分词
Hanlp:有一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用
THULAC:THU Lexical Analyzer for Chinese,有清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能
elasticsearch写入流程:
1、将数据写入内存缓存区
2、然后将数据写到translog缓存区
3、每隔1s数据从buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能通过索引查询到了
4、refresh完,memory buffer就清空了。
5、每隔5s中,translog 从buffer flush到磁盘中
6、定期/定量从FileSystemCache中,结合translog内容flush index到磁盘中。
kibana 语法:
创建带有自定义分析器的索引:
PUT /test
{
"settings": {
"number_of_shards" : 1, #主片
"number_of_replicas" : 0, #副片
"analysis": {
"char_filter": { #字符过滤器
"&_to_and": {
"type": "mapping",
"mappings": [ "_=> ' ' "] #将'_'替换成' ' 空格
}},
"filter": {
"my_stopwords": { #词单元过滤器
"type": "stop",
"stopwords": [ "the", "a" ] #删除单词 'the'、'a'
}},
"analyzer": {
"my_analyzer": { #分词器
"type": "custom", #custom 自定义分析器
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "ik_max_word",
"filter": [ "lowercase", "my_stopwords" ]
}}
}
},
"mappings": {
"properties":{
"tableName": {
"analyzer": "my_analyzer", #规定分析器
"type": "text"
}
}
}
}
添加数据
POST /test/_doc
{
"tableName":"tm_dc_t010_hr_js_count_manual_d"
}
删除索引
DELETE /test
查询:
POST /test/_search
{
"query": {
"match": {
"tableName": "dc_t010"
}
},
"highlight": {
"fields": {
"tableName": {} #使用默认高亮 <em></em>
}
}
}
索引下分析器 分析文本:
POST /test/_analyze
{
"analyzer": "my_analyzer", #my_analyzer 为索引下 分析器
"text": "tm_dc_t200_hr_js_count_manual_d"
}
java api:
1、创建搜索请求对象
//1、无参
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("index1","index2");
//2、有参
SearchRequest searchRequest = new SearchRequest("index1","index2");
创建请求对象后,参数为字符串Stirng类型,逗号隔开即可查看多个索引
2、查询文档类型:已经取消
searchRequest.types("doc1");
searchRequest.types("doc1", "doc1", "doc2");
支持查询一个类型或者多个类型,逗号隔开即可
7.x该api已经取消
3、设置指定查询的路由分片
searchRequest.routing("routing");
4、用preference方法去指定优先去某个分片上去查询(默认的是随机先去某个分片)
searchRequest.preference("_local");
5、创建 搜索内容参数设置对象:
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//分页,from起始页为0,size当前页的数量
searchSourceBuilder.from((pageNum-1)*10);
searchSourceBuilder.size(pageSize);
高亮显示:
//创建高亮显示对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
//选中字段进行高亮显示
highlightBuilder.field("tableName");//高亮查询字段
highlightBuilder.requireFieldMatch(false); //如果要多个字段高亮,这项要为false
//重写高亮显示 方式,默认
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//将高亮显示添加到搜索内容参数设置对象
searchSourceBuilder.highlighter(highlightBuilder);
查询条件:
//查询所有的内容
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//创建多条件查询对象,boolQueryBuilder可使用must、filter、should,
//其中使用must:返回的文档必须满足must子句的条件,并且参与计算分值
//filter:返回的文档必须满足filter子句的条件,但是不会像must一样,参与计算分值
//should:返回的文档可能满足should子句的条件.在一个bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回.minimum_should_match参数定义了至少满足几个子句。
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.matchQuery("tableName",keyword).analyzer("ik_max_word").boost(2));
boolQueryBuilder.should(QueryBuilders.matchQuery("tableComment",keyword).analyzer("ik_smart"));
//搜索内容参数设置对象添加 条件对象
searchSourceBuilder.query(boolQueryBuilder).sort("_score", SortOrder.DESC);
//设置查询请求的超时时间:如下表示60秒没得到返回结果时就认为请求已超时
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(searchSourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//查询结果集的总数量
long total=search.getHits().getTotalHits().value;
for (SearchHit hit : search.getHits()) {
HighlightField tableName = highlightFields.get("tableName");
//原来的结果
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//解析高亮字段,将原来的字段换为我们高亮字段即可
if(tableName!=null){
Text[] fragments = tableName.fragments();
String n_title="";
for(Text text:fragments){
n_title += text;
}
sourceAsMap.put("tableName",n_title);
}
}