四、初探[ElasticSearch]集群架构原理与搜索技术

news2024/11/16 13:54:21

目录

  • 一、浅析Elasticsearch架构原理
    • 1.Elasticsearch的节点类型
      • 1.1 Master节点
      • 1.2DataNode节点
  • 二、分片和副本机制
    • 2.1分片
    • 2.2副本
    • 2.3指定分片、副本数量
    • 2.4查看分片、主分片、副本分片
  • 三、Elasticsearch工作流程
    • 3.1Elasticsearch文档写入原理
    • 3.2Elasticsearch检索原理
  • 四、Elasticsearch准实时索引实现
    • 4.1溢写到文件系统缓存
    • 4.2写translog保障容错
    • 4.3flush到磁盘(刷盘)
    • 4.4segment合并
  • 五.手动控制搜索结果精准度
    • 5.1operator与minimum_should_match简单使用
    • 5.2、match 的底层转换
    • 5.3、boost权重控制
    • 5.4、基于dis_max实现best fields策略进行多字段搜索
    • 5.5、基于tie_breaker参数优化dis_max搜索效果
    • 5.6、使用multi_match简化dis_max+tie_breaker(不常用)
    • 5.7、cross_fields搜索
    • 5.8、copy_to组合fields
    • 5.9、近似匹配
    • 5.10、match_phrase
      • 5.10.1match phrase原理 —— term position
      • 5.10.2match phrase搜索参数 -- slop
    • 5.11使用match和proximity search实现召回率和精准度平衡。
    • 5.12前缀搜索 prefix search
    • 5.13通配符搜索
    • 5.14正则搜索
    • 5.15搜索推荐
    • 5.16fuzzy模糊搜索技术

一、浅析Elasticsearch架构原理

1.Elasticsearch的节点类型

在Elasticsearch主要分成两类节点,一类是Master,一类是DataNode。

1.1 Master节点

在Elasticsearch启动时,会选举出来一个Master节点。采用Zen Discovery1机制选出master节点并且找到集群中的其他节点,并建立连接。一个Elasticsearch集群中,只有一个Master节点。(这里的一个是在集群范围中的,而不是指定某台服务器一直就是主节点,主节点所在服务器宕机,其他的某一个节点有机会成为master节点)

Master节点主要功能::

  1. 管理索引和分片的创建、删除和重新分配。
  2. 监测节点的状态,并在需要时进行重分配。
  3. 协调节点之间的数据复制和同步工作。
  4. 处理集群级别操作,如创建或删除索引、添加或删除节点等。
  5. 维护集群的健康状态,并在集群出现问题时采取措施解决。
  6. 维护元数据2

1.2DataNode节点

与master节点不同,datanode节点可能会有多个。这个取决于你集群的节点数量,因为master在集群中只能有一个,其余为DataNode节点。
DataNode节点主要功能:

  1. 存储和索引数据:Data Node 节点会将索引分片存储在本地磁盘上,并对查询请求进行响应。
  2. 复制和同步数据:为了确保数据的可靠性和高可用性,ElasticSearch 会将每个原始分片的多个副本存储在不同的 Data Node 节点上,并定期将各节点上的数据进行同步。
  3. 参与搜索和聚合操作:当客户端提交搜索请求时,Data Node 节点会使用本地缓存和分片数据完成搜索和聚合操作。
  4. 执行数据维护操作:例如,清理过期数据和压缩分片等。

二、分片和副本机制

在第一篇文章中也有介绍过这俩个概念,这里在集群中再次进行解释
在这里插入图片描述

2.1分片

ElasticSearch是一个分布式的搜索引擎,索引索引可以分成一份或多份,多份分片分布在不同节点当中。ElasticSearch会自动管理分片,如果发现分片分布不均衡,就会自动迁移。

2.2副本

在ElasticSearch中每个分片都有一个主分片,可能会有若干个副本分片(默认一个分片,一个副本),这些副本也会分布在不同的节点上。

2.3指定分片、副本数量

PUT /test_index06
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword",
        "index": true,
        "store": true
      },
      ................
    }
  },
  //设置分片数量1,副本数量2
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 2
  }
}

2.4查看分片、主分片、副本分片

GET /_cat/indices?v

三、Elasticsearch工作流程

3.1Elasticsearch文档写入原理

在这里插入图片描述

如何知道我插入一条数据要保存到那个分片呢?

shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id。
number_of_primary_shards为分片数量
你也可以使用自己的自定义分片键,只需在索引时指定"_routing"字段即可。

3.2Elasticsearch检索原理

在这里插入图片描述
客户端发起查询请求,某个DataNode接收到请求,该DataNode就会成为协调节点。
协调节点(Coordinating Node)将查询请求广播到每一个数据节点,这些数据节点的分片会处理该查询请求, 每个分片进行数据查询,将符合条件的数据放在一个优先队列中,并将这些数据的文档ID、节点信息、分片信息返回给协调节点。
协调节点将所有的结果进行汇总,并进行全局排序, 协调节点向包含这些文档ID的分片发送get请求,对应的分片将文档数据返回给协调节点,最后协调节点将数据返回给客户端。

四、Elasticsearch准实时索引实现

在这里插入图片描述

4.1溢写到文件系统缓存

当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘)ES中默认1秒,refresh缓存一次。

4.2写translog保障容错

在写入到内存中的同时,也会记录translog日志,在refresh期间出现异常,会根据translog来进行数据恢复
等到文件系统缓存中的segment数据都刷到磁盘中,清空translog文件。

4.3flush到磁盘(刷盘)

ES默认每隔30分钟会将文件系统缓存的数据刷入到磁盘。

4.4segment合并

Segment太多时,ES定期会将多个segment合并成为大的segment,减少索引查询时IO开销,此阶段ES会真正的物理删除(之前执行过的delete的数据)。

五.手动控制搜索结果精准度

5.1operator与minimum_should_match简单使用

①查询document中的remark字段包含java或developer词组。

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": "java developer"
    }
  }
}

或者这样查询

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer",
        "operator": "or"
      }
    }
  }
}

结果

 "hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.77041256,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.21110919,
        "_source" : {
          "name" : "天王盖地虎",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java"
        }
      }
    ]

②查询document中的remark字段,同时包含java和developer词组

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer",
        "operator": "and"
      }
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.77041256,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      }
    ]

③minimum_should_match可以使用百分比或固定数字。百分比代表query搜索条件中词条百分比,如果无法整除,向下匹配(如,query条件有3个单词,如果使用百分比提供精准度计算,那么是无法除尽的,如果需要至少匹配两个单词,则需要用67%来进行描述。如果使用66%描述,ES则认为匹配一个单词即可)。固定数字代表query搜索条件中的词条,至少需要匹配多少个。
③-1百分比
查询内容包括java 或developer或assistant中匹配度达到66%即文档内容中,至少包括一个单词出现。

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer assistant",
        "minimum_should_match": "66%"
      }
    }
  }
}
"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.21110919,
        "_source" : {
          "name" : "天王盖地虎",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.160443,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      }
    ]

查询内容包括java 或architect 或assistant中匹配度达到67%即文档内容中,至少包括两个个单词出现。

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer assistant",
        "minimum_should_match": "67%"
      }
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.77041256,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      }
    ]

③-2固定数字
查询的内容中至少出现下面三个条件中的两个,即java、developer、assistant这三个单词,至少有两个同时出现才符合条件。

GET /test_index05/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "remark": "java"
          }
        },
        {
          "match": {
            "remark": "developer"
          }
        },
        {
          "match": {
            "remark": "assistant"
          }
        }
      ],
      "minimum_should_match": 2
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.77041256,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      }
    ]

5.2、match 的底层转换

我们输入的查询语句

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": "java developer"
    }
  }
}

转换后的查询语句

GET /test_index05/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "remark": "java"
          }
        },
        {
          "term": {
            "remark": {
              "value": "developer"
            }
          }
        }
      ]
    }
  }
}

查询语句

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer",
        "operator": "and"
      }
    }
  }
}

转换后

GET /test_index05/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "remark": "java"
          }
        },
        {
          "term": {
            "remark": {
              "value": "developer"
            }
          }
        }
      ]
    }
  }
}

查询条件

GET /test_index05/_search
{
  "query": {
    "match": {
      "remark": {
        "query": "java developer assistant",
        "minimum_should_match": "68%"
      }
    }
  }
}

转换后

GET /test_index05/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "remark": "java"
          }
        },
        {
          "term": {
            "remark": "developer"
          }
        },
        {
          "term": {
            "remark": "assistant"
          }
        }
      ],
      "minimum_should_match": 2
    }
  }
}

使用转换后的语法执行搜索,效率更高。

5.3、boost权重控制

搜索document中remark字段中包含java的数据,如果remark中包含developer或assistant,则包含assistant的document优先显示。(就是将assistant数据匹配时的相关度分数增加)。
一般用于搜索时相关度排序使用。如:电商中的综合排序。将一个商品的销量,广告投放,评价值,库存,单价比较综合排序。在上述的排序元素中,广告投放权重最高,库存权重最低。还有就是百度搜索内容时前几一般都是广告。

例如
索引test_index05下全部数据为

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "天王盖地虎",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "铁锅炖大鹅",
          "sex" : 1,
          "age" : 19,
          "address" : "天津",
          "remark" : "java assistant"
        }
      }
    ]

查询(boost越高,表示权重越高,越优先展示)

GET /test_index05/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "remark": "java"
          }
        }
      ],
      "should": [
        {
          "match": {
            "remark": {
              "query": "developer",
              "boost": 1
            }
          }
        },
        {
          "match": {
            "remark": {
              "query": "assistant",
              "boost": 3
            }
          }
        }
      ]
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 2.3016074,
        "_source" : {
          "name" : "铁锅炖大鹅",
          "sex" : 1,
          "age" : 19,
          "address" : "天津",
          "remark" : "java assistant"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.474477,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.43250346,
        "_source" : {
          "name" : "天王盖地虎",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java"
        }
      }
    ]

查询

GET /test_index05/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "remark": "java"
          }
        }
      ],
      "should": [
        {
          "match": {
            "remark": {
              "query": "developer",
              "boost": 2
            }
          }
        },
        {
          "match": {
            "remark": {
              "query": "assistant",
              "boost": 1
            }
          }
        }
      ]
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 2.611973,
        "_source" : {
          "name" : "宝塔镇河妖",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.9918565,
        "_source" : {
          "name" : "铁锅炖大鹅",
          "sex" : 1,
          "age" : 19,
          "address" : "天津",
          "remark" : "java assistant"
        }
      },
      {
        "_index" : "test_index05",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.43250346,
        "_source" : {
          "name" : "天王盖地虎",
          "sex" : 1,
          "age" : 25,
          "address" : "上海",
          "remark" : "java"
        }
      }
    ]

5.4、基于dis_max实现best fields策略进行多字段搜索

best_fields策略: 搜索的document中的某一个field,尽可能多的匹配搜索条件。
most_fields策略:与best fields相反的是,尽可能多的字段匹配到搜索条件。

dis_max语法: 直接获取搜索的多条件中的,单条件query相关度分数最高的数据,以这个数据做相关度排序。

best fields策略实现举例(是找name字段中’秀儿’匹配相关度分数或remark字段中’java developer’匹配相关度分数,哪个高,就使用哪一个相关度分数进行结果排序。)

GET /test_index06/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "remark": "java developer"
          }
        },
        {
          "match": {
            "name": "秀儿"
          }
        }
      ]
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vkjNUIcB14FuHovqnIz1",
        "_score" : 2.3842063,
        "_source" : {
          "name" : "秀儿",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 1.781607,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vUjNUIcB14FuHovqaYzA",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "rods",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "python developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "v0jOUIcB14FuHovqTYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Tom",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "wEjOUIcB14FuHovqYYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Amy",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      }
    ]

5.5、基于tie_breaker参数优化dis_max搜索效果

我不想根据打分最高的那个字段进行排序展示,我想让其他的字段也参与进来咋办?

dis_max是将多个搜索query条件中相关度分数最高的用于结果排序,忽略其他query分数,在某些情况下,可能还需要其他query条件中的相关度介入最终的结果排序,这个时候可以使用tie_breaker参数来优化dis_max搜索。tie_breaker参数代表的含义是:将其他query搜索条件的相关度分数乘以参数值,再参与到结果排序中。如果不定义此参数,相当于参数值为0。所以其他query条件的相关度分数被忽略。

tie_breaker指定的值最大为1,除最高分字段,设置其他字段打分的策略,即其他字段得分乘指定的系数,如果不加这个tie_breaker则默认为0

GET /test_index06/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "remark": "java developer"
          }
        },
        {
          "match": {
            "name": "秀儿"
          }
        }
      ],
      "tie_breaker": 0.5
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vkjNUIcB14FuHovqnIz1",
        "_score" : 2.5047874,
        "_source" : {
          "name" : "秀儿",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 1.781607,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vUjNUIcB14FuHovqaYzA",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "rods",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "python developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "v0jOUIcB14FuHovqTYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Tom",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "wEjOUIcB14FuHovqYYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Amy",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      }
    ]

5.6、使用multi_match简化dis_max+tie_breaker(不常用)

ES中相同结果的搜索也可以使用不同的语法语句来实现。

查询方式1

GET /test_index06/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "name": "Tom"
          }
        },
        {
          "match": {
            "remark": {
              "query": "java developer",
              "boost": 2,
              "minimum_should_match": 2
            }
          }
        }
      ],
      "tie_breaker": 0.5
    }
  }
}

结果

"hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 3.563214,
    "hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 3.563214,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "v0jOUIcB14FuHovqTYw0",
        "_score" : 1.6360589,
        "_source" : {
          "name" : "Tom",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      }
    ]

查询方式2(其中type常用的有best_fields和most_fields。^n代表权重,相当于"boost":n。)

GET /test_index06/_search
{
  "query": {
    "multi_match": {
      "query": "Tom java developer",
      "fields": [
        "name",
        "remark^2"
      ],
      "type": "best_fields",
      "tie_breaker": 0.5,
      "minimum_should_match": "50%"
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 3.563214,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "v0jOUIcB14FuHovqTYw0",
        "_score" : 1.877221,
        "_source" : {
          "name" : "Tom",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vUjNUIcB14FuHovqaYzA",
        "_score" : 0.48232412,
        "_source" : {
          "name" : "rods",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "python developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vkjNUIcB14FuHovqnIz1",
        "_score" : 0.48232412,
        "_source" : {
          "name" : "秀儿",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "wEjOUIcB14FuHovqYYw0",
        "_score" : 0.48232412,
        "_source" : {
          "name" : "Amy",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      }
    ]

5.7、cross_fields搜索

cross fields : 一个唯一的标识,分部在多个fields中,使用这种唯一标识搜索数据就称为cross fields搜索。如:人名可以分为姓和名,地址可以分为省、市、区县、街道等。那么使用人名或地址来搜索document,就称为cross fields搜索。实现这种搜索,一般都是使用most fields搜索策略。因为这就不是一个field的问题。Cross fields搜索策略,是从多个字段中搜索条件数据。默认情况下,和most fields搜索的逻辑是一致的,计算相关度分数是和best fields策略一致的。一般来说,如果使用cross fields搜索策略,那么都会携带一个额外的参数operator。用来标记搜索条件如何在多个字段中匹配。在ES中也有cross fields搜索策略

例如(搜索条件中的java必须在name或remark字段中匹配,developer也必须在name或remark字段中匹配。)

GET /test_index06/_search
{
  "query": {
    "multi_match": {
      "query": "java developer",
      "fields": [
        "name",
        "remark"
      ],
      "type": "cross_fields",
      "operator": "and"
    }
  }
}

结果

"hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.781607,
    "hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 1.781607,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      }
    ]

most field策略问题:most fields策略是尽可能匹配更多的字段,所以会导致精确搜索结果排序问题。又因为cross fields搜索,不能使用minimum_should_match来去除长尾数据。所以在使用most fields和cross fields策略搜索数据的时候,都有不同的缺陷。所以商业项目开发中,都推荐使用best fields策略实现搜索。

5.8、copy_to组合fields

场景:在电商网站,如果在搜索框中输入“手机”,点击搜索,那么是在商品的类型名称、商品的名称、商品的卖点、商品的描述等字段中,哪一个字段内进行数据的匹配?如果使用某一个字段做搜索不合适,那么使用_all做搜索是否合适?也不合适,因为_all字段中可能包含图片,价格等字段。

假设,有一个字段,其中的内容包括(但不限于):商品类型名称、商品名称、商品卖点等字段的数据内容。是否可以在这个特殊的字段上进行数据搜索匹配?(我理解的就是融合多个字段为一个,理解为该商品的摘要信息。)

以keyword字段举例,它包括了category_name、product_name、sell_point三个字段的内容。

{
  "category_name" : "手机",
  "product_name" : "一加6T手机",
  "price" : 568800,
  "sell_point" : "国产Android手机",
  "tags": ["8G+128G", "256G可扩展"],
  "color" : "红色",
  "keyword" : "手机 一加6T手机 国产Android手机"
}

copy_to : 就是将多个字段,复制到一个字段中,实现一个多字段组合。copy_to可以解决cross fields搜索问题,在商业项目中,也用于解决搜索条件默认字段问题。 如果需要使用copy_to语法,则需要在定义index的时候,手工指定mapping映射策略。

例如

PUT /test_index07/_mapping
{
  "properties": {
    "provice": {
      "type": "text",
      "analyzer": "standard",
      "copy_to": "address"
    },
    "city": {
      "type": "text",
      "analyzer": "standard",
      "copy_to": "address"
    },
    "street": {
      "type": "text",
      "analyzer": "standard",
      "copy_to": "address"
    },
    "address": {
      "type": "text",
      "analyzer": "standard"
    }
  }
}

上述的mapping定义中,是新增了4个字段,分别是provice、city、street、address,其中provice、city、street三个字段的值,会自动复制到address字段中,实现一个字段的组合。那么在搜索地址的时候,就可以在address字段中做条件匹配,从而避免most fields策略导致的问题。在维护数据的时候,不需对address字段特殊的维护。因为address字段是一个组合字段,是由ES自动维护的。类似java代码中的推导属性。在存储的时候,未必存在,但是在逻辑上是一定存在的,因为address是由3个物理存在的属性province、city、street组成的。

5.9、近似匹配

给定一个短语,或者单词,匹配包含全部或者部分的内容。

举例(test_index06中remark字段没有go相关内容)

GET /test_index06/_search
{
  "query": {
    "match": {
      "remark": "developer go"
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vUjNUIcB14FuHovqaYzA",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "rods",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "python developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vkjNUIcB14FuHovqnIz1",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "秀儿",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "v0jOUIcB14FuHovqTYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Tom",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      },
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "wEjOUIcB14FuHovqYYw0",
        "_score" : 0.24116206,
        "_source" : {
          "name" : "Amy",
          "sex" : 1,
          "age" : 26,
          "book" : "Spring",
          "remark" : "C developer"
        }
      }
    ]

举例

GET /test_index06/_search
{
  "query": {
    "match": {
      "remark": "developerAA"
    }
  }
}

结果

"hits" : [ ]

如果需要的结果是有特殊要求,如:java developer 必须是一个完整的短语,不可分割;或document中的field内,包含的java 和developer 单词,且两个单词之间离的越近,相关度分数越高。那么这种特殊要求的搜索就是近似搜索。 搜索包括javb内容,搜索条件在java developer数据中搜索,或包括 j 搜索提示等数据近似搜索的一部分。如何上述特殊要求的搜索,使用match搜索语法就无法实现了。

5.10、match_phrase

短语搜索。就是搜索条件不分词。代表搜索条件不可分割。

举例(只会匹配出,java developer同时出现,并且连续的内容,即java developer为一个整体出现)

GET /test_index06/_search
{
  "query": {
    "match_phrase": {
      "remark": "java developer"
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index06",
        "_type" : "_doc",
        "_id" : "vEjNUIcB14FuHovqKIyb",
        "_score" : 1.7816072,
        "_source" : {
          "name" : "rod",
          "sex" : 1,
          "age" : 25,
          "book" : "Spring",
          "remark" : "java developer"
        }
      }
    ]

5.10.1match phrase原理 —— term position

ES是如何实现match phrase短语搜索的?其实在ES中,使用match phrase做搜索的时候,也是和match类似,首先对搜索条件进行分词-analyze。将搜索条件拆分成hello和world。既然是分词后再搜索,ES是如何实现短语搜索的?
这里涉及到了倒排索引的建立过程。在倒排索引建立的时候,ES会先对document数据进行分词,如:

查询如下句子是如何分词的

GET _analyze
{
  "text": "hello world, java spark",
  "analyzer": "standard"
}

结果

{
  "tokens" : [
    {
      "token" : "hello",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "world",
      "start_offset" : 6,
      "end_offset" : 11,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "java",
      "start_offset" : 13,
      "end_offset" : 17,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "spark",
      "start_offset" : 18,
      "end_offset" : 23,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}

从上述结果中,可以看到。ES在做分词的时候,除了将数据切分外,还会保留一个position。position代表的是这个词在整个数据中的下标。当ES执行match phrase搜索的时候,首先将搜索条件hello world分词为hello和world。然后在倒排索引中检索数据,如果hello和world都在某个document的某个field出现时,那么检查这两个匹配到的单词的position是否是连续的,如果是连续的,代表匹配成功,如果是不连续的,则匹配失败。

5.10.2match phrase搜索参数 – slop

场景举例:在做搜索操作的是,如果搜索参数是hello spark。而ES中存储的数据是hello world, java spark。那么使用match phrase则无法搜索到。在这个时候,可以使用match来解决这个问题。但是,当我们需要在搜索的结果中,做一个特殊的要求:hello和spark两个单词距离越近,document在结果集合中排序越靠前,这个时候再使用match则未必能得到想要的结果。

ES的搜索中,对match phrase提供了参数slop。slop代表match phrase短语搜索的时候,单词最多移动多少次,可以实现数据匹配。在所有匹配结果中,多个单词距离越近,相关度评分越高,排序越靠前。这种使用slop参数的match phrase搜索,就称为近似匹配(proximity search)

在Elasticsearch中,slop是指在查询语句中,词项之间可以允许的最大距离。它是一种模糊匹配(fuzzy matching)方式,用于解决用户输入错误或者数据存储时不准确的情况。
当我们进行一个带有slop参数的查询时,Elasticsearch将按照文档中出现的顺序检查查询语句中的每个词,并尝试找到它们之间最接近的匹配。如果两个词之间的距离小于或等于slop的值,则它们被认为是匹配的。
例子:
假设我们有以下三个文档:

{
  "id": 1,
  "title": "quick brown fox"
}
{
  "id": 2,
  "title": "quick red fox"
}
{
  "id": 3,
  "title": "slow brown dog"
}

我们希望查找包含“quick”和“fox”的文档,并且它们之间的最大距离为1。我们可以使用以下查询:

{
  "query": {
    "match_phrase": {
      "title": {
        "query": "quick fox",
        "slop": 1
      }
    }
  }
}

该查询将返回文档1和2,但不会返回文档3,因为“slow”和“brown”之间的距离大于1。(关于距离你可以去看下对应的position字段,即match phrase原理 —— term position下讲解的内容)

需要注意的是,slop值越大,匹配的结果会越多,但是精度也会降低。因此,在使用slop时,需要根据实际情况进行权衡。

5.11使用match和proximity search实现召回率和精准度平衡。

召回率:召回率就是搜索结果比率,如:索引A中有100个document,搜索时返回多少个document,就是召回率(recall)。
精准度:就是搜索结果的准确率,如:搜索条件为hello java,在搜索结果中尽可能让短语匹配和hello java离的近的结果排序靠前,就是精准度(precision)。
如果在搜索的时候,只使用match phrase语法,会导致召回率低下,因为搜索结果中必须包含短语(包括proximity search)。
如果在搜索的时候,只使用match语法,会导致精准度底下,因为搜索结果排序是根据相关度分数算法计算得到。
那么如果需要在结果中兼顾召回率和精准度的时候,就需要将match和proximity search混合使用,来得到搜索结果。

索引test_index08下所有内容

"hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "f" : "java and spark, development language "
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.0,
        "_source" : {
          "f" : "java spark and, development language "
        }
      }
    ]

查询1

GET /test_index08/_search
{
  "query": {
    "match": {
      "f": "java spark"
    }
  }
}

结果

"hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 0.28046143,
    "hits" : [
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.28046143,
        "_source" : {
          "f" : "java and spark, development language "
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 0.28046143,
        "_source" : {
          "f" : "java spark and, development language "
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.23111339,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.16973917,
        "_source" : {
          "f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."
        }
      }
    ]

查询2

GET /test_index08/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "f": "java spark"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "f": {
              "query": "java spark",
              "slop": 50
            }
          }
        }
      ]
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 0.56092286,
        "_source" : {
          "f" : "java spark and, development language "
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.4815065,
        "_source" : {
          "f" : "java and spark, development language "
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.32339638,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      },
      {
        "_index" : "test_index08",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 0.30782324,
        "_source" : {
          "f" : "Java Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs."
        }
      }
    ]

5.12前缀搜索 prefix search

使用前缀匹配实现搜索能力。通常针对keyword类型字段,也就是不分词的字段。

GET /test_a/_mapping
{
  "test_a" : {
    "mappings" : {
      "properties" : {
        "f" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

所有数据如下

"hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      },
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "f" : "java and spark, development language "
        }
      }
    ]

查询

GET /test_a/_search
{
  "query": {
    "prefix": {
      "f.keyword": {
        "value": "j"
      }
    }
  }
}

结果

    "hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "f" : "java and spark, development language "
        }
      }
    ]

查询

GET /test_a/_search
{
  "query": {
    "prefix": {
      "f.keyword": {
        "value": "J"
      }
    }
  }
}

结果

"hits" : [ ]

针对前缀搜索,是对keyword类型字段而言。而keyword类型字段数据大小写敏感。前缀搜索效率比较低。前缀搜索不会计算相关度分数。前缀越短,效率越低。如果使用前缀搜索,建议使用长前缀。因为前缀搜索需要扫描完整的索引内容,所以前缀越长,相对效率越高。

5.13通配符搜索

通配符可以在倒排索引中使用,也可以在keyword类型字段中使用。
(性能很低,也是需要扫描完整的索引)
? :表示一个任意字符
*·:表示0~n个任意字符
查询

GET /test_a/_search
{
  "query": {
    "wildcard": {
      "f.keyword": {
        "value": "?e*o*"
      }
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      }
    ]

5.14正则搜索

在Elasticsearch中,regexp查询是一种使用正则表达式进行搜索的查询方式。它可以在指定字段上匹配满足正则表达式的文本。

ES支持正则表达式,可以在倒排索引或keyword类型字段中使用。
例如,假设我们有一个包含文档标题和内容的索引,并想要查找所有标题或内容中包含“Elastic”和“search”的文档。这时候,就可以使用regexp查询来实现:

{
    "query": {
        "regexp": {
            "_all": ".*Elastic.*search.*"
        }
    }
}

在上述例子中,“_all” 表示对所有字段进行搜索,".*"表示任意字符出现0次或多次。

需要注意的是,正则表达式的查询效率较低,因为它需要对每个文档的每个字段都进行逐一匹配。如果对性能要求较高,应该尽量避免使用正则表达式查询。

另外,Elasticsearch还支持设置正则表达式的参数,如ignore_case(是否忽略大小写),max_determinized_states(最大化自动机状态数),boost(权重系数),以及flags(正则表达式标志)。这些参数可以提高查询的准确性和灵活性。

再举例

GET /test_a/_search
{
  "query": {
    "regexp": {
      "f.keyword": "[A-z].+"
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      },
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "f" : "java and spark, development language "
        }
      }
    ]

性能很低,需要扫描完整索引,应该尽量避免在大型索引中使用

5.15搜索推荐

在Elasticsearch中,match_phrase_prefix查询是一种结合了match和prefix两种查询的组合查询。它可以用于匹配以指定前缀开头的短语。

具体来说,match_phrase_prefix查询会先将查询字符串拆分成一个个词项(term),然后使用前缀匹配算法进行匹配。通常情况下,match_phrase_prefix查询适用于需要匹配长短语但又希望支持前缀匹配的场景。
搜索推荐: search as your type, 搜索提示。如:索引中有若干数据以“hello”开头,那么在输入hello的时候,推荐相关信息。(类似百度输入框)

查询

GET /test_a/_search
{
  "query": {
    "match_phrase_prefix": {
      "f": {
        "query": "java s",
        "slop": 10,
        "max_expansions": 10
      }
    }
  }
}

结果

"hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.28650534,
        "_source" : {
          "f" : "java and spark, development language "
        }
      },
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.11460209,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      }
    ]

其原理和match phrase类似,是先使用match匹配term数据(java),然后在指定的slop移动次数范围内,前缀匹配(s),max_expansions是用于指定prefix最多匹配多少个term(单词),超过这个数量就不再匹配了。
这种语法的限制是,只有最后一个term会执行前缀搜索。
执行性能很差,最后一个term是需要扫描所有符合slop要求的倒排索引的term。
因为效率较低,如果必须使用,则一定要使用参数max_expansions。

5.16fuzzy模糊搜索技术

Elasticsearch中的fuzzy模糊搜索技术是一种基于编辑距离(Levenshtein Distance)算法的全文检索技术。它允许在查询时匹配相似但不完全相同的单词。具体来说,当我们进行一个fuzzy query时,Elasticsearch将会在索引中查找与查询字符串最接近的项。如果查询字符串中有一个拼写错误或者一个字符丢失,fuzzy search可以帮助我们找到那些被错误拼写的项。另外,fuzzy search也能够在搜索时匹配多个单词之间的相似性。在Elasticsearch中,我们可以使用fuzziness参数来设置模糊度,该参数表示最大编辑距离,即允许的最大差异数量。默认值为2,这意味着如果两个单词的编辑距离超过2,则它们将不会被匹配。我们可以通过增加或减少该参数来调整模糊度,以便更好地满足我们的需求。

搜索的时候,可能搜索条件文本输入错误,如:hello world -> hello word。这种拼写错误还是很常见的。fuzzy技术就是用于解决错误拼写的(在英文中很有效,在中文中几乎无效。)。其中fuzziness代表value的值word可以修改多少个字母来进行拼写错误的纠正(修改字母的数量包含字母变更,增加或减少字母。)。f代表要搜索的字段名称。
查询

GET /test_a/_search
{
  "query": {
    "fuzzy": {
      "f": {
        "value": "word",
        "fuzziness": 2
      }
    }
  }
}

结果

 "hits" : [
      {
        "_index" : "test_a",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.43569255,
        "_source" : {
          "f" : "hello, java is very good, spark is also very good"
        }
      }
    ]

  1. Zen Discovery 是 Elasticsearch 中的一种自动发现机制,它用于在分布式环境下管理节点的发现和连接。Zen Discovery 能够自动感知节点的加入和离开,并在必要时重新分配数据和重新平衡群集。
    Zen Discovery 机制包括以下几个方面:
    1.Ping 操作:每个节点会定期向其他节点发送 ping 请求,以确定其他节点是否还在运行。如果一个节点在一定时间内没有响应,那么它就被认为已经离开了群集。
    2.Unicast 发现:节点之间可以通过互相发送地址列表来进行发现。在这种方式下,节点需要知道其他节点的 IP 地址和端口号,才能够加入群集。当节点启动时,它会向配置的节点列表发送加入请求,如果请求成功,则会将该节点加入群集。
    3.Multicast 发现:在使用 Multicast 发现机制时,节点可以通过多播地址来进行发现。每个节点将自己的 IP 地址和端口号发布到特定的多播地址上,其他节点可以从该地址上接收到所有节点的信息,从而发现新的节点。这种方式下,节点可以更加灵活地管理群集,可以随时加入和离开群集。
    4.Master 选举:Zen Discovery 还包括了 Master 节点的选举机制,选举出的 Master 节点会负责协调群集中的各个节点。
    (当然,在某些情况下,可能需要手动指定主节点或禁用主节点竞选过程。可以通过在 elasticsearch.yml 配置文件中设置 node.master 参数来实现。如果将该参数设置为 false,则表示禁用该节点的主节点竞选功能;如果将该参数设置为 true,则表示该节点可以参与主节点竞选。默认情况下,所有节点都会参与主节点竞选,因此无需手动配置。) ↩︎

  2. 在 ElasticSearch 集群中,Master 节点维护的元数据包括以下信息:
    1.集群状态:保存了当前集群的状态,如运行状态、健康状态等。
    2.索引元数据:保存了所有索引的信息,例如字段映射、分片数量、副本数量、索引别名等。
    3.节点元数据:保存了所有节点的信息,例如 IP 地址、节点名称、可用空间、JVM 信息等。
    4.分片分配信息:保存了每个分片所属的节点信息、是否是主分片等。
    5.节点故障检测信息:保存了节点最近一次的心跳信息和下线时间,用于检测节点是否失效。
    这些元数据都存储在 Master 节点的内存中,并与其他节点进行同步,以确保集群中所有节点都拥有相同的元数据视图。通过 Master 节点维护这些元数据,可以实现集群管理和协调,确保数据的高可用性、一致性和完整性。 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/612156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java开发手册中为什么要求三目运算符必须要注意类型对齐

场景 java开发手册中对于三目运算符的使用要求如下: 【强制】三目运算符 condition? 表达式 1 : 表达式 2 中&#xff0c;高度注意表达式 1 和 2 在类型对齐时&#xff0c; 可能抛出因自动拆箱导致的 NPE 异常。 说明&#xff1a;以下两种场景会触发类型对齐的拆箱操作&am…

华为路由器 NAT 配置

拓扑图 静态 NAT 静态地址转换是指外部网络和内部网络之间的地址映射关系由配置确定&#xff0c;该方式适用于内部网络与外部网络之间存在固定访问需求的组网环境。静态地址转换支持双向互访&#xff1a;内网用户可以主动访问外网&#xff0c;外网用户也可以主动访问内网。 一…

2023国际管理会计教育联盟发展论坛在沪成功召开

2023年5月7日&#xff0c;由教育部中外人文交流中心、国际管理会计教育联盟&#xff08;下称“联盟”&#xff09;主办&#xff0c;中国商业会计学会、上海交通大学安泰经济与管理学院承办的2023国际管理会计教育联盟发展论坛&#xff08;下称“发展论坛”&#xff09;在上海成…

第4章:SpringMVC的域对象共享数据

1、使用ServletAPI向request域对象共享数据 ①控制器 Controller public class HelloController {RequestMapping("/test")public String index(HttpServletRequest request){request.setAttribute("test","test666");return "index"…

避坑之网上下单的手机流量卡为什么老是失败!

最近有一些小伙伴们反应&#xff1a;在网上下单的手机流量卡&#xff0c;经常提示下单失败&#xff0c;不是这问题就是那问题的。 对于小伙伴们的诉求&#xff0c;小编向来是来者不拒的。今天就为大家整理一下下单失败的四大原因。 失败原因一&#xff1a;下单信息填写错误 下…

javax.validation常用注解

javax.validation 提供了一系列的注解&#xff0c;用于在 Java Bean 中对属性进行验证&#xff0c;主要有以下几种&#xff1a; NotNull&#xff1a;验证对象不可为 null&#xff1b;NotEmpty&#xff1a;验证字符串&#xff0c;数组&#xff0c;Collection&#xff0c;Map不可…

软件工程期末题目分析

一、软件工程概论 1.当你准备参与开发一个系统的时候&#xff0c;如果你对这个系统的问题领域不是很熟悉&#xff0c;那么最好不要采用以下哪种系统开发模型&#xff1f;&#xff08;A&#xff09; A、瀑布模型B、原型模型C、螺旋模型D、喷泉模型 瀑布模型模型要求用户需求明…

Selenium浏览器自动化怎么上传文件

Selenium 封装了现成的文件上传操作。但是随着现代前端框架的发展&#xff0c;文件上传的方式越来越多样。而有一些文件上传的控件&#xff0c;要做自动化控制会更复杂一些&#xff0c;这篇文章主要讨论在复杂情况下&#xff0c;如何通过自动化完成文件上传。 1. input 元素上传…

Windows 脚本批量打开文件

Windows 脚本批量打开文件 应用场景 对自己个人而言&#xff0c;每次学习某个内容&#xff0c;要打开一系列学习文档、代码和网页 可应用于执行某个任务需要一次性打开多个文件的场景。 方法 脚本内容 echo offstart "" "E:\Records\WebDesignLearning\la…

【iOS】--响应者链

响应者链 iOS响应者链是一种事件处理机制&#xff0c;它描述了在iOS系统中&#xff0c;当一个事件&#xff08;比如用户点击屏幕或者发送手势&#xff09;发生时&#xff0c;它将从触发事件的源头开始&#xff0c;按照预定义的顺序传递给各个视图或控件进行处理&#xff0c;直…

搭建Nextcloud私有云【零基础搭建私有云盘并内网穿透远程访问】

文章目录 摘要视频教程1. 环境搭建2. 测试局域网访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问 4 配置固定http公网地址4.1 保留一个二级子域名4.1 配置固定二级子域名4.3 测试访问公网固定二级子域名 转载自cpolar极点云的文章&#xff1a;使用Nextcl…

chatgpt赋能python:Python同名变量:了解Python变量定义规则和注意事项

Python同名变量&#xff1a;了解Python变量定义规则和注意事项 Python作为一门高级编程语言&#xff0c;拥有着灵活性和可读性&#xff0c;广泛应用于软件开发、数据分析和人工智能领域。在Python编程中&#xff0c;变量是非常重要的概念&#xff0c;在程序中扮演着存储和读取…

基于大模型构建本地知识库

基于大模型构建本地知识库 图文概述一、知识库构建1.文本加载和读取2.文本分割3.文本向量化英文排行版中文SOTA 二、向量搜索1.向量存储2.用户问题向量化3.知识库中搜索和问题最相似的topK个向量 三、大模型理解四、问题 图文概述 一、知识库构建 1.文本加载和读取 支持的格式…

Arm NN 成功适配 openEuler Embedded,提供高性能神经网络推理能力

近期&#xff0c;RISC-V SIG 完成了 Arm NN 在 openEuler Embedded 系统的适配&#xff0c;于 2023 年 1 月合入系统构建工程代码库&#xff0c;经测试验证可用&#xff0c;实现了神经网络加速库在 openEuler Embedded 嵌入式系统上的加速和优化。 系统构建工程下载地址&#x…

AUTOSAR通信篇-CAN网络通信(三:PduR)

文章目录 PduR简介I-PDU缓存缓存区类型缓存策略缓存共享 I-PDU接收接收来自通信接口的I-PDU接收来自传输协议的I-PDU I-PDU发送通信接口型发送传输协议型发送多播传输处理未知长度I-PDU I-PDU网关通信接口网关缓存立即网关 传输协议直接网关On-the-fly网关 发送取消接收取消零损…

海睿思分享 | 主数据如何赋能企业运营管理

在全球范围内&#xff0c;企业正在越来越多地依赖数据进行决策和运营。然而&#xff0c;由于数据量的爆炸式增长以及数据来源的多样化&#xff0c;管理这些数据以获取有效的洞见变得越来越困难。 主数据管理&#xff08;MDM&#xff09;作为一种方法和技术&#xff0c;旨在帮助…

XSS跨站脚本安全漏洞防护

文章目录 1 跨站脚本1.1 存储型XSS1.2 反射型XSS 2 、案例2.1 通过正则表达式替换跨站脚本2.2 构建请求的代理类&#xff0c;在构造方法中对请求中的内容进行分析2.3 构建响应的代理类2.4 通过Filter过滤掉请求和响应中的跨站脚本 3 测试3.1 在接口的body参数中添加一个脚本3.2…

半导体(TSS)放电管的两大选购注意事项及选型小策略

固体放电管&#xff0c;是以半导体工艺制作而成的&#xff0c;因此我们也称为半导体&#xff08;TSS&#xff09;放电管&#xff0c;它常在电路中并联使用&#xff0c;具备伏安特性。 TSS放电管在电路中类似开关&#xff0c;在正常工作时不动作&#xff0c;但一般被保护电路受到…

华为OD机试题【支持优先级的队列】【2023 B卷 100分】

文章目录 &#x1f3af; 前言&#x1f3af; 题目描述&#x1f3af; 解题思路&#x1f4d9; Python代码实现&#x1f4d7; Java代码实现&#x1f4d8; C语言代码实现 &#x1f3af; 前言 &#x1f3c6; 《华为机试真题》专栏含2023年牛客网面经、华为面经试题、华为OD机试真题最…

悲观锁、乐观锁、自旋锁

悲观锁、乐观锁、自旋锁 &#xff08;1&#xff09;乐观锁 乐观锁是一种乐观的思想&#xff0c;即认为读多写少&#xff0c;遇到并发的可能性低&#xff0c;每次拿数据时都认为别人不会修改&#xff0c;所以不会上锁&#xff0c;但是在更新的时候会判断一下在此期间别人有没有…