elasticsearch入门详解以及mapping介绍

elasticsearch简介

Elastic 的底层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。
中文文档链接: https://es.xiaoleilu.com/010_Intro/30_Tutorial_Search.html
官方网站:https://www.elastic.co/cn/

elasticsearch的Type区别

核心数据类型:

1.字符串类型:text、keyworde(不分词)
2.数值型:long、integer、short、byte、dobule、float、half_float等
3.日期类型: date
4.布尔类型: boolean
5.二进制类型: binary
6.范围类型:integer_range、float_range、long_range、double_range、date_range

复杂数据类型

1.数组类型:array
2.对象类型:object
3.嵌套类型:nested object
4.地理位置数据类型:geo_point、geo_shape
5.专用类型:ip(记录ip地址)、completion(实现自动补全)、token_count(记录分词数)、murmur3(记录字符串hash值)

倒排索引

在这里插入图片描述

index内部模型

在这里插入图片描述

自动识别规则

在不指定type值的情况需下,String默认为text并且有一个子字段keyword。
指定分词器创建索引:

PUT test4_bean
{
    "settings": {
        "analysis": {
            "analyzer":{
              "ik_max_word":{
                  "tokenizer":"ik_max_word"
                   }
            }
        }
    },
    "mappings": {
        "test4_bean": {
            "properties": {
                "testStringKW": {
                    "type": "keyword"
                },
                "categoryId": {
                    "type": "long"
                },
                "testStringIk": {
                    "type": "text",
                    "analyzer": "ik_max_word"
                }
            }
        }
    }
}

public class TestBean {

    @Id
    private Long categoryId;

    /**
     * 类别名称
     */
    private String testString;

    @Field(type = FieldType.Keyword)
    private String testStringKW;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String testStringIk;

}
{
  "mapping": {
    "test_bean": {
      "properties": {
        "categoryId": {
          "type": "long"
        },
        "testString": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "testString123": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "testStringIk": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "testStringKW": {
          "type": "keyword"
        }
      }
    }
  }
}

匹配查询

elasticsearch 中term与match区别

term是精确查询
match是模糊查询

使用QueryBuilder
* termQuery(“key”, obj) 完全匹配
* termsQuery(“key”, obj1, obj2…) 一次匹配多个值
* matchQuery(“key”, Obj) 单个匹配, field不支持通配符, 前缀具高级特性(会分词)
* matchPhraseQuery(“key”, Obj) 单个匹配, field不支持通配符, 前缀具高级特性(短语 不分词)
* multiMatchQuery(“text”, “field1”, “field2”…); 匹配多个字段, field有通配符忒行
* matchAllQuery(); 匹配所有文件
* fuzzyQuery 模糊查询(个人尝试,结果并不如意)
* wildcardQuery模糊查询 (类似mysql的like匹配,属于精确查询)

multiMatchQuery

中文单字:默认>ik>keyword

MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("测", "testString");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(multiMatchQueryBuilder);

MultiMatchQueryBuilder multiMatchQueryBuilderIk = QueryBuilders.multiMatchQuery("测","testStringIk");
BoolQueryBuilder queryBuilderIk = QueryBuilders.boolQuery().must(multiMatchQueryBuilderIk);

MultiMatchQueryBuilder multiMatchQueryBuilderKw = QueryBuilders.multiMatchQuery("测", "testStringKW");
BoolQueryBuilder queryBuilderKw = QueryBuilders.boolQuery().must(multiMatchQueryBuilderKw);
结果:
CategoryBean=[TestBean(categoryId=255357, testString=预测未知, testStringKW=预测未知, testStringIk=预测未知), TestBean(categoryId=276288, testString=预测未
size=4
Total=4
CategoryBeanIk=[TestBean(categoryId=281402, testString=策测解金8, testStringKW=策测解金8, testStringIk=策测解金8)]        
sizeIk=1
TotalIk=1
CategoryBeanKw=[]
sizeKw=0
TotalKw=0

纯英文:ik>默认>keyword
主要是引文ik会将英文跟数字进行分词处理,而默认的不会
由于纯英文不会分词,所以这种查询方法并不推荐。(还有许多匹配数据没出来 例如:dskfjggg)

MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("gg", "testString");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(multiMatchQueryBuilder);

MultiMatchQueryBuilder multiMatchQueryBuilderIk = QueryBuilders.multiMatchQuery("gg","testStringIk");
BoolQueryBuilder queryBuilderIk = QueryBuilders.boolQuery().must(multiMatchQueryBuilderIk);

MultiMatchQueryBuilder multiMatchQueryBuilderKw = QueryBuilders.multiMatchQuery("gg", "testStringKW");
BoolQueryBuilder queryBuilderKw = QueryBuilders.boolQuery().must(multiMatchQueryBuilderKw);
结果:
CategoryBean=[TestBean(categoryId=246141, testString=范德萨gg, testStringKW=范德萨gg, testStringIk=范德萨gg), TestBean(categoryId=259385, testString=GG思密达, testStringKW=GG思密达, testStringIk=GG思密达)]
size=2
Total=2
CategoryBeanIk=[TestBean(categoryId=259385, testString=GG思密达, testStringKW=GG思密达, testStringIk=GG思密达), TestBean(categoryId=206079, testString=gg0117, testStringKW=gg0117, testStringIk=gg0117), TestBean(categoryId=246141, testString=范德萨gg, testStringKW=范德萨gg, testStringIk=范德萨gg)]
sizeIk=3
TotalIk=3
CategoryBeanKw=[]
sizeKw=0
TotalKw=0

wildcardQuery

相当于mysql的like匹配
默认=ik>keyword
我做的测试里面默认的是等于ik因为这个跟分词无关,但是keyword会少一点,是因为不区分大小写。
ik与默认分词其实也不能够区分大小写,在我用“GG”测试的时候,默认与ik都没有找到数据,keyword能找到数据。
解决此问题可以参考 链接 :https://blog.csdn.net/wessiyear/article/details/79281181

WildcardQueryBuilder wildcardQueryBuilder1 = QueryBuilders.wildcardQuery("testString","*gg*");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(wildcardQueryBuilder1);

WildcardQueryBuilder wildcardQueryBuilderIk = QueryBuilders.wildcardQuery("testStringIk","*gg*");
BoolQueryBuilder queryBuilderIk = QueryBuilders.boolQuery().must(wildcardQueryBuilderIk);

WildcardQueryBuilder wildcardQueryBuilderKw = QueryBuilders.wildcardQuery("testStringKW","*gg*");
BoolQueryBuilder queryBuilderKw = QueryBuilders.boolQuery().must(wildcardQueryBuilderKw);
结果:
CategoryBean=[TestBean(categoryId=248259, testString=GGYY社长, testStringKW=GGYY社长, testStringIk=GGYY社长), TestBean(categoryId=251580, testString=GGQQ, testStringKW=GGQQ, testStringIk=GGQQ),....
size=10
Total=24
CategoryBeanIk=[TestBean(categoryId=248259, testString=GGYY社长, testStringKW=GGYY社长, testStringIk=GGYY社长), TestBean(categoryId=251580, testString=GGQQ, testStringKW=GGQQ, testStringIk=GGQQ).....
sizeIk=10
TotalIk=24
CategoryBeanKw=[TestBean(categoryId=249214, testString=aggie, testStringKW=aggie, testStringIk=aggie), TestBean(categoryId=206079, testString=gg0117, testStringKW=gg0117, testStringIk=gg0117).....
sizeKw=10
TotalKw=21

should用法

相当于or查询

WildcardQueryBuilder wildcardQueryBuilder1 = QueryBuilders.wildcardQuery("testString","*aa*");
WildcardQueryBuilder wildcardQueryBuilder2 = QueryBuilders.wildcardQuery("testString","*gg*");
WildcardQueryBuilder wildcardQueryBuilder3 = QueryBuilders.wildcardQuery("testString","*123*");
//        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(wildcardQueryBuilder1);
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().should(wildcardQueryBuilder1).should(wildcardQueryBuilder2).should(wildcardQueryBuilder3);
结果:
CategoryBean=[TestBean(categoryId=249161, testString=agg123, testStringKW=agg123, testStringIk=agg123), TestBean(categoryId=257418, testString=wzq123, testStringKW=wzq123, testStringIk=wzq123), TestBean(categoryId=257468, testString=liaowen123, testStringKW=liaowen123, testString.....
size=10
Total=180

keyword解决大小写问题

生成:

PUT test_bean
{
    "settings": {
        "analysis": {
            "normalizer": {
                "lowercase": {
                "type": "custom",
                "filter": [
                    "lowercase"
                  ]
                }
            }
        }
    },
    "mappings": {
        "test_bean": {
            "properties": {
                "testStringKW": {
                    "type": "keyword"
                },
                "categoryId": {
                    "type": "long"
                },
                "testString": {
                    "type": "text",
                    "fields":{
                      "keyword":{
                        "type":"keyword",
                        "ignore_above":256
                      }
                    }
                },
                "testStringIk": {
                    "type": "text",
                    "analyzer": "ik_max_word"
                },
                "test_bean": {
                    "type": "keyword",
                    "normalizer": "lowercase"
              }
            }
        }
    }
}

或者代码中

json文件放到 resource下:

{
  "index": {
    "analysis": {
      "normalizer": {
        "lower_case_normalizer": {
          "type": "custom",
          "char_filter": [],
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  }
}
mapping:

```java
{
  "mapping": {
    "test_bean": {
      "properties": {
        "categoryId": {
          "type": "long"
        },
        "testString": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "testStringIk": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "testStringKW": {
          "type": "keyword"
        },
        "test_bean": {
          "type": "keyword",
          "normalizer": "lowercase"
        }
      }
    }
  }
}

api使用

分词效果测试

POST test_bean/_analyze
{
  "field": "testStringIk", 
  "text": "你弘法寺方艾欧是"
}

POST _analyze
{
  "tokenizer": "standard", 
  "filter": ["lowercase"], 
  "text": "Hello world"
}


POST _analyze
{
  "analyzer": "ik_max_word", 
  "text": "你好中国,我爱北京"
}

POST _analyze
{
  "tokenizer": "keyword", 
  "char_filter": ["html_strip"], 
  "text": "<p>I&apos;m s"
}

POST _analyze
{
  "tokenizer": "ngram", 
  "text": "sjfjkajfskljfsal"
}

POST _analyze
{
  "tokenizer": "path_hierachy", 
  "text":"/abc/oijo/jgbad"
}

POST _analyze
{
  "text":"拜仑财经真的很不错",
  "tokenizer": "standard",
  "filter": [
    "stop",
    "lowercase",
    {
      "type":"ngram",
      "min_gram":1,
      "max_gram":2
    }
    ]
}

自定义分词器结构

自定义分词器结构
无论是内置的分析器(analyzer),还是自定义的分析器(analyzer),都由三种构件块组成的:character filters , tokenizers , token filters。

内置的analyzer将这些构建块预先打包到适合不同语言和文本类型的analyzer中。

Character filters (字符过滤器)

字符过滤器以字符流的形式接收原始文本,并可以通过添加、删除或更改字符来转换该流。

举例来说,一个字符过滤器可以用来把阿拉伯数字(٠‎١٢٣٤٥٦٧٨‎٩)‎转成成Arabic-Latin的等价物(0123456789)。

一个分析器可能有0个或多个字符过滤器,它们按顺序应用。

(PS:类似Servlet中的过滤器,或者拦截器,想象一下有一个过滤器链)

Tokenizer (分词器)

一个分词器接收一个字符流,并将其拆分成单个token (通常是单个单词),并输出一个token流。例如,一个whitespace分词器当它看到空白的时候就会将文本拆分成token。它会将文本“Quick brown fox!”转换为[Quick, brown, fox!]

(PS:Tokenizer 负责将文本拆分成单个token ,这里token就指的就是一个一个的单词。就是一段文本被分割成好几部分,相当于Java中的字符串的 split )

分词器还负责记录每个term的顺序或位置,以及该term所表示的原单词的开始和结束字符偏移量。(PS:文本被分词后的输出是一个term数组)

一个分析器必须只能有一个分词器

Token filters (token过滤器)

token过滤器接收token流,并且可能会添加、删除或更改tokens。

例如,一个lowercase token filter可以将所有的token转成小写。stop token filter可以删除常用的单词,比如 the 。synonym token filter可以将同义词引入token流。

不允许token过滤器更改每个token的位置或字符偏移量。

一个分析器可能有0个或多个token过滤器,它们按顺序应用。

stop 接受以下参数:

stopwords : 一个预定义的停止词列表(比如,englisht)或者是一个包含停止词的列表。默认是 english
stopwords_path : 包含停止词的文件路径。这个路径是相对于Elasticsearch的config目录的一个路径
stopwords指定停词

PUT test4_bean
{
    "settings": {
        "analysis": {
            "analyzer":{
              "ik_max_word":{
                  "tokenizer":"ik_max_word",
                  "type":"stop",
                  "stopwords":["你爸爸","他哥"]
                   }
            }
        }
    },
    "mappings": {
        "test4_bean": {
            "properties": {
                "testStringKW": {
                    "type": "keyword"
                },
                "categoryId": {
                    "type": "long"
                },
                "testStringIk": {
                    "type": "text",
                    "analyzer": "ik_max_word"
                }
            }
        }
    }
}

stopwords_path指定停词(好像只能识别txt文件)

PUT test4_bean
{
    "settings": {
        "analysis": {
            "analyzer":{
              "ik_max_word":{
                  "tokenizer":"ik_max_word",
                  "filter":["extra_stop"]
                   }
            },
            "filter": {
              "extra_stop":{
                "type":"stop",
                "stopwords_path":"analysis-ik/extra_stopword.txt"
              }
            }
            
        }
    },
    "mappings": {
        "test4_bean": {
            "properties": {
                "testStringKW": {
                    "type": "keyword"
                },
                "categoryId": {
                    "type": "long"
                },
                "testStringIk": {
                    "type": "text",
                    "analyzer": "ik_max_word"
                }
            }
        }
    }
}
POST test4_bean/_analyze
{
  "analyzer": "ik_max_word",
  "text": "你好中国,你爸爸,我也爱北京a你是谁"
}

ik添加分词器

IKAnalyzer.cfg.xml的配置例如以下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户能够在这里配置自己的扩展字典 <entry key="ext_dict">ext.dic;</entry>假设有多个扩展词典。那么以分号分隔就可以,如以下的两个扩展停止词字典 -->
	<!--用户能够在这里配置自己的扩展停止词字典 -->
	<entry key="ext_stopwords">stopword.dic;chinese_stopwords.dic</entry>
</properties>

注意点:

1、停用词词典必须是UTF-8编码。

2、这里非常多跟我一样的新手没办法成功的原因就是被无bom的UTF-8格式给折磨的,IK作者自己也这样说了。

3、假设你不知道啥叫无BOM,也不确定自己的文件是不是UTF-8无bom,那么请在第一行使用回车换行,从第二行開始加入停止词。

4、该配置文件以及停用词词典均存放在src文件夹以下就可以。

示例示例
示例结果
在这里插入图片描述

自定义示例

在这里插入图片描述
效果示例:
在这里插入图片描述

深度分页

from/size 需要实时获取顶部的部分文档,且需要自由翻页
scroll 快照 需要全部文档,如到处所有数据的功能
search_after 下一页 需要全部文档,不需要自由翻页

参考资料:
elasticsearch使用指南 : https://www.cnblogs.com/yueshutong/p/9381543.html
elasticsearch的mapping: https://blog.csdn.net/sinat_35930259/article/details/80354732

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值