ES实现MySQL中的where xx = xx and ((条件1) or (条件2) or (条件3))

本文详细解析了在 Elasticsearch 中使用 must 和 should 等布尔运算符时可能遇到的问题。当 must 存在时,should 条件变得可有可无,导致搜索结果不符合预期。文章提供了两种解决方案:一是设置 `minimum_should_match` 参数确保 should 条件至少匹配一项;二是将 should 放置于 must 的子级中。通过 Java API 示例展示了如何实现这些解决方案,帮助开发者避免搜索陷阱并优化查询逻辑。

must和should同时存在的坑

        

        这个地方有个坑,就是当 must 和 should 同时存在的时候,should就成为了可有可无的了,只要must满足就可以,must就是mysql中的and, should就是or,

        即 当must存在的时候,should中的条件是可有可无的,就是must条件满足就行,should的一个都不用满足也可以,当must不存在的时候,should中的条件至少要满足一个。

        例如我先使用merchantName匹配一个公司,

 

        现在我在加上该数据的merchantId必须满足should条件中的一个,你会发现并没有什么用,搜索出来的数据merchantId明明不满足我们的搜索条件之一,但是依然搜索出来了,就是因为有了must后,should中不满足也会被搜出来,

GET /xxxx/xxx/_search
{
   
  "query": {
    "bool": {
      "must": [
          {
          "term": {
            "merchantName.keyword": "xxxxxx有限公司"
          }
        }
      ],
      "should": [
        {
          "bool" : {
            "must" : [
              {
                "term" : {
                  "merchantId" : {
                    "value" : 111
                  }
                }
              }
            ]
          }
        },
        {
          "bool" : {
            "must" : [
              {
                "term" : {
                  "merchantId" : {
                    "value" : 112
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

 

        当我们把must删除以后,会发现should生效了,此时不满足should中的条件的数据将不会被查询出来,

 

        

解决方式一

        在查询条件中增加 "minimum_should_match":1,意为should条件中必须要满足其中之一,可以看到,加上该条件后,数据已经无法查出了,因为should中的条件无法满足其中之一,

 

        去除后,则又查询出来了,

 

Java Api写法

BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// merchantName
queryBuilder.must(QueryBuilders.termQuery("merchantName", "xxxx"));
// should merchantId        queryBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("merchantId", 111))); queryBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("merchantId", 222)));
queryBuilder.minimumShouldMatch(1);

解决方式二

        之前的should和must是平级的,我们可以将should放在must的子级中也可以解决这个问题,

GET /xxx/xxx/_search
{
	"query": {
		"bool": {
			"must": [
			  {
					"term": {
						"merchantName.keyword": "合肥眷念商贸有限公司"
					}
				},
				{
					"bool": {
							"should": [{
									"bool": {
										"must": [{
											"term": {
												"merchantId": {
													"value": 111
												}
											}
										}]
									}
								},
								{
									"bool": {
										"must": [{
											"term": {
												"merchantId": {
													"value": 112
												}
											}
										}]
									}
								}
							]
					}
				}
			]
		}
	}
}

        将条件匹配上后,则查询出来了

 

Java Api写法

BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// merchantName
queryBuilder.must(QueryBuilders.termQuery("merchantName", "xxxx"));
// should merchantId
BoolQueryBuilder queryDCBuilder = QueryBuilders.boolQuery();
queryDCBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("merchantId", 111)));
queryDCBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("merchantId", 222)));
queryBuilder.must(queryDCBuilder);

 

        

<!-- 主查询:只查询主表信息 --> <select id="queryPurchaseOrderPage" resultType="com.hvlink.entity.dto.order.PurchaseOrderMainDTO"> SELECT m.id, m.company_code, m.purchase_order_no, m.publish_date, s.supplier_code, s.supplier_name, f.factory_code, f.factory_name, w.warehouse_code, w.warehouse_name, m.serial_version_num, m.order_type FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY purchase_order_no, company_code ORDER BY serial_version_num DESC) as rn FROM tb_order_main WHERE is_deleted = 0 ) m LEFT JOIN tm_supplier s ON m.supplier_code = s.supplier_code AND m.company_code = s.company_code LEFT JOIN tm_factory f ON m.factory_code = f.factory_code AND m.company_code = f.company_code LEFT JOIN tm_warehouse w ON m.warehouse_code = w.warehouse_code AND m.company_code = w.company_code <where> m.rn = 1 <!-- 只取每个订单的最新版本 --> <!-- 优化后的模糊匹配组 --> <if test="param.supplierName != null and param.supplierName != &#39;&#39; or param.supplierCode != null and param.supplierCode != &#39;&#39; or param.factoryName != null and param.factoryName != &#39;&#39; or param.factoryCode != null and param.factoryCode != &#39;&#39; or param.warehouseName != null and param.warehouseName != &#39;&#39; or param.warehouseCode != null and param.warehouseCode != &#39;&#39;"> AND ( <trim prefixOverrides="OR"> <!-- 供应商条件 --> <if test="param.supplierName != null and param.supplierName != &#39;&#39;"> OR s.supplier_name LIKE &#39;%&#39; + #{param.supplierName} + &#39;%&#39; </if> <if test="param.supplierCode != null and param.supplierCode != &#39;&#39;"> OR s.supplier_code LIKE &#39;%&#39; + #{param.supplierCode} + &#39;%&#39; </if> <!-- 工厂条件 --> <if test="param.factoryName != null and param.factoryName != &#39;&#39;"> OR f.factory_name LIKE &#39;%&#39; + #{param.factoryName} + &#39;%&#39; </if> <if test="param.factoryCode != null and param.factoryCode != &#39;&#39;"> OR f.factory_code LIKE &#39;%&#39; + #{param.factoryCode} + &#39;%&#39; </if> <!-- 仓库条件 --> <if test="param.warehouseName != null and param.warehouseName != &#39;&#39;"> OR w.warehouse_name LIKE &#39;%&#39; + #{param.warehouseName} + &#39;%&#39; </if> <if test="param.warehouseCode != null and param.warehouseCode != &#39;&#39;"> OR w.warehouse_code LIKE &#39;%&#39; + #{param.warehouseCode} + &#39;%&#39; </if> </trim> ) </if> <!-- 订单号模糊查询 --> <if test="param.purchaseOrderNo != null and param.purchaseOrderNo != &#39;&#39;"> AND m.purchase_order_no LIKE &#39;%&#39; + #{param.purchaseOrderNo} + &#39;%&#39; </if> <if test="param.startDate != null"> AND m.publish_date >= #{param.startDate} </if> <if test="param.endDate != null"> AND m.publish_date <= #{param.endDate} </if> <!-- 订单类型 --> <if test="param.orderType != null"> AND m.order_type = #{param.orderType} </if> <!-- 明细字段关联查询 - 使用EXISTS优化性能 --> <if test="param.partCode != null and param.partCode != &#39;&#39;"> AND EXISTS ( SELECT 1 FROM tb_order_detail d WHERE d.purchase_order_no = m.purchase_order_no AND d.company_code = m.company_code AND d.serial_version_num = m.serial_version_num AND d.part_code LIKE &#39;%&#39; + #{param.partCode} + &#39;%&#39; ) </if> <if test="param.partDesc != null and param.partDesc != &#39;&#39;"> AND EXISTS ( SELECT 1 FROM tb_order_detail d WHERE d.purchase_order_no = m.purchase_order_no AND d.company_code = m.company_code AND d.serial_version_num = m.serial_version_num AND d.part_desc LIKE &#39;%&#39; + #{param.partDesc} + &#39;%&#39; ) </if> <if test="param.frequency != null and param.frequency != &#39;&#39;"> AND EXISTS ( SELECT 1 FROM tb_order_detail d WHERE d.purchase_order_no = m.purchase_order_no AND d.company_code = m.company_code AND d.serial_version_num = m.serial_version_num AND d.frequency = #{param.frequency} ) </if> </where> ORDER BY s.supplier_code DESC, m.purchase_order_no DESC </select> <select id="selectLatestByOrderIds" resultType="com.hvlink.entity.dto.order.PurchaseOrderMainDTO"> SELECT m.id, m.company_code, m.purchase_order_no, m.publish_date, s.supplier_code, s.supplier_name, f.factory_code, f.factory_name, w.warehouse_code, w.warehouse_name, m.serial_version_num, m.order_type FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY purchase_order_no, company_code ORDER BY serial_version_num DESC) as rn FROM tb_order_main WHERE is_deleted = 0 AND id IN <foreach collection="orderIds" item="id" open="(" close=")" separator=","> #{id} </foreach> ) m LEFT JOIN tm_supplier s ON m.supplier_code = s.supplier_code AND m.company_code = s.company_code LEFT JOIN tm_factory f ON m.factory_code = f.factory_code AND m.company_code = f.company_code LEFT JOIN tm_warehouse w ON m.warehouse_code = w.warehouse_code AND m.company_code = w.company_code WHERE m.rn = 1 ORDER BY m.create_time DESC </select> 进行性能优化,并帮我检查是否有错误
最新发布
09-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值