將字符串 “()“ ““ “|“ 條件組成的復雜表達式轉換為ES查詢語句

應用場景

"()" "&" "|"? 這幾個條件對于我們來說并不陌生, 其表達的邏輯非常明了, 又能通過很少的字符表達很復雜的嵌套關系, 在一些復雜的查詢中會經常用到, 因此我最近也遇到了類似的問題,一開始覺得這類的工具應該挺常見的, 結果搜了半天沒有找到合適的,因此決定自己寫一個

簡介

此工具的復雜之處在于我們并不確定操作系統的人員會輸入怎樣的表達式,格式并不是固定的因此可能會書寫出較為復雜的邏輯. 也有可能只嵌套一層就結束了,所以我們的代碼一定要考慮的通用

此處我簡單說一下它的原理, 主要是用到了一個java中棧的概念: 這個工具通過解析輸入的邏輯查詢字符串,使用棧來管理運算符和操作數,構建出對應的查詢樹,然后將其轉換為Elasticsearch的多字段(如標題、摘要、正文)的搜索查詢,實現復雜的邏輯查詢條件的自動解析和執行。

以下代碼全部都加了注釋, 應該是不難理解的?

代碼

package com.sinosoft.springbootplus.lft.business.dispatch.publicopinion.util;import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;import java.util.Stack;/*** 構建ES復雜查詢條件,包含括號、邏輯運算符和操作符** @author zzt* @date 2024-05-28*/
public class ESQueryParserUtil {/*** 解析輸入字符串并將其轉換為Elasticsearch的QueryBuilder** @param query 輸入的查詢字符串* @return Elasticsearch的QueryBuilder*/public static SearchSourceBuilder parseQuery(String query) {// 存儲運算符的棧Stack<Character> operators = new Stack<>();// 存儲操作數的棧Stack<QueryBuilder> operands = new Stack<>();for (int i = 0; i < query.length(); i++) {char ch = query.charAt(i);if (ch == '(' || ch == '&' || ch == '|') {// 遇到左括號或者運算符時,壓入運算符棧operators.push(ch);} else if (ch == ')') {// 遇到右括號時,彈出運算符棧中的運算符并進行計算直到遇到左括號while (!operators.isEmpty() && operators.peek() != '(') {char operator = operators.pop();QueryBuilder right = operands.pop();QueryBuilder left = operands.pop();operands.push(applyOperator(left, right, operator));}operators.pop(); // 彈出左括號} else if (Character.isLetterOrDigit(ch) || ch == ' ') {// 遇到字母、數字、空格或者“地區”時,構建查詢字符串StringBuilder sb = new StringBuilder();while (i < query.length() && (Character.isLetterOrDigit(query.charAt(i)) || query.charAt(i) == ' ')) {sb.append(query.charAt(i));i++;}i--; // 回退一個字符,因為外層for循環會前進一個字符operands.push(QueryBuilders.multiMatchQuery(sb.toString().trim(), "title", "sysAbstract", "content"));//此處是我的ES中要模糊搜索的三個字段, 這里請自行更改}}// 處理剩余的運算符while (!operators.isEmpty()) {char operator = operators.pop();QueryBuilder right = operands.pop();QueryBuilder left = operands.pop();operands.push(applyOperator(left, right, operator));}return new SearchSourceBuilder().query(operands.pop());}/*** 根據運算符將兩個操作數組合成一個QueryBuilder** @param left     左操作數* @param right    右操作數* @param operator 運算符* @return 組合后的QueryBuilder*/private static QueryBuilder applyOperator(QueryBuilder left, QueryBuilder right, char operator) {BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();if (operator == '&') {boolQuery.must(left).must(right);} else if (operator == '|') {boolQuery.should(left).should(right);}return boolQuery;}public static void main(String[] args) {String query = "((北京|天津|(河北&石家莊))&(打架|辱罵|違法))&(中國)";SearchSourceBuilder searchSourceBuilder = parseQuery(query);System.out.println(searchSourceBuilder);}
}

?生成的查詢條件

由于我寫的這個算是稍微復雜一點的嵌套,生成的查詢條件還是挺長的, 感興趣的可以試一下

{"query": {"bool": {"must": [{"bool": {"must": [{"bool": {"should": [{"multi_match": {"query": "北京","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}},{"bool": {"should": [{"multi_match": {"query": "天津","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}},{"bool": {"must": [{"multi_match": {"query": "河北","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}},{"multi_match": {"query": "石家莊","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}},{"bool": {"should": [{"multi_match": {"query": "打架","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}},{"bool": {"should": [{"multi_match": {"query": "辱罵","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}},{"multi_match": {"query": "違法","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}},{"multi_match": {"query": "中國","fields": ["content^1.0","sysAbstract^1.0","title^1.0"],"type": "best_fields","operator": "OR","slop": 0,"prefix_length": 0,"max_expansions": 50,"zero_terms_query": "NONE","auto_generate_synonyms_phrase_query": true,"fuzzy_transpositions": true,"boost": 1.0}}],"adjust_pure_negative": true,"boost": 1.0}}
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21161.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21161.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21161.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM垃圾收集器和內存分配策略

概述 Java內存運行時數據區的程序計數器、虛擬機棧、本地方法棧3個區域會隨著線程而產生&#xff0c;隨線程而消失。這幾個區域分配多少內存時在類結構確定下來即已知的&#xff0c;在這幾個區域內就不需要過多考慮如何回收內存的問題&#xff0c;當方法結束或者線程結束時&am…

【spring】第一篇 IOC和DI入門案例

Spring到底是如何來實現IOC和DI的&#xff0c;那接下來就通過一些簡單的入門案例&#xff0c;來演示下具體實現過程。 目錄 前期準備 一、IOC入門案例 思路分析 代碼實現 二、DI入門案例 思路分析 代碼實現 總結 前期準備 使用IDEA創建Maven項目&#xff0c;首先需要配…

JAVAEE1

Web前端&#xff1a; 1.建立web開發的息維模式寫代碼不僅僅是為了實現某個功能&#xff0c;更是學習解決問題的思維方式 2.先使用&#xff0c;再理解&#xff0c;會導致剛開始比較懵&#xff0c;不知其所以然.切忌不可深陷其中&#xff0c; 3.涉及簡單的軟件工程的設計思想&…

Springboot整合kafka簡單使用

kafka 一&#xff0c;介紹 Kafka 是一個開源的分布式流處理平臺&#xff0c;最初由 LinkedIn 開發并貢獻給 Apache 軟件基金會。它設計用于構建高性能、持久性、可伸縮和容錯的實時數據管道和流處理應用程序。 以下是 Kafka 的一些關鍵特點和概念&#xff1a; 發布-訂閱模型…

SPWM載波調制方式-三電平雜記1

方法一&#xff1a; P2 O1 N0 方法二&#xff1a;雙載波直接發波 方法三&#xff1a;負軸載波和調制波往上抬升1&#xff0c;得到使用同一個載波 在正半周在P和O切換&#xff0c;在下半軸式O和N切換

自動評論自動私信引流系統,自動化時代的挑戰與機遇

隨著科技的飛速發展&#xff0c;自動化技術已經滲透到我們生活的方方面面。從工業生產線上的機械臂到家庭中的智能助手&#xff0c;自動化不僅改變了我們的工作方式&#xff0c;也在重塑著社會的面貌。然而&#xff0c;在享受自動化帶來的便利和效率的同時&#xff0c;我們也必…

961題庫 北航計算機 MIPS基礎選擇題 附答案 選擇題形式

有題目和答案&#xff0c;沒有解析&#xff0c;不懂的題問大模型即可&#xff0c;無償分享。 第1組 習題 MIPS處理器五級流水線中&#xff0c;涉及DRAM的是 A. 取指階段 B. 譯碼階段 C. 執行階段 D. 訪存階段 MIPS處理器五級流水線中&#xff0c;R型指令保存結果的階段是 A.…

關于高版本 Plant Simulation 每次保存是 提示提交comm對話框的處理方法

關于高版本 Plant Simulation 每次保存是 提示提交comm對話框的處理方法 如下圖 將model saving history 修改為None即可 關于AutoCAD 2022 丟失模板庫的問題 從新從以下地址打開即可&#xff1a; D:\Program Files\Autodesk\AutoCAD 2022\UserDataCache\zh-cn\Template

Visual Studio Installer 點擊閃退

Visual Studio Installer 點擊閃退問題 1. 問題描述2. 錯誤類型3. 解決方法4. 結果5. 說明6. 參考 1. 問題描述 重裝了系統后&#xff08;系統版本&#xff1a;如下圖所示&#xff09;&#xff0c;我從官方網站&#xff08;https://visualstudio.microsoft.com/ ) 下載了安裝程…

Leetcode:正則表達式匹配

目錄 普通版本&#xff08;動態規劃&#xff09; 狀態表示 狀態轉移方程 優化③①情況 數學化簡分析 結合實際情況畫圖化簡分析 總結 最終代碼 題目鏈接&#xff1a;10. 正則表達式匹配 - 力扣&#xff08;LeetCode&#xff09; 好像是leetcode前100道里面最難的一道&a…

方法引用與構造方法引用

目錄 方法引用 什么是方法引用 構造方法引用 構造方法引用&#xff08;也可以稱作構造器引用&#xff09; 數組構造方法引用 方法引用 什么是方法引用 當要傳遞給 Lambda 體的操作&#xff0c;已經有實現的方法了&#xff0c;可以使用方法引用。 方法引用可以看做是 La…

PHAR反序列化

PHAR PHAR&#xff08;PHP Archive&#xff09;文件是一種歸檔文件格式&#xff0c;phar文件本質上是一種壓縮文件&#xff0c;會以序列化的形式存儲用戶自定義的meta-data。當受影響的文件操作函數調用phar文件時&#xff0c;會自動反序列化meta-data內的內容,這里就是我們反序…

頭歌頁面置換算法第3關:計算LRU算法缺頁率

2 任務:LRU算法 2.1 任務描述 設計LRU頁面置換算法模擬程序:從鍵盤輸入訪問串。計算LRU算法在不同內存頁框數時的缺頁數和缺頁率。要求程序模擬駐留集變化過程,即能模擬頁框裝入與釋放過程。 2.2任務要求 輸入串長度作為總頁框數目,補充程序完成LRU算法。 2.3算法思路 LRU算…

jmeter常用的斷言

包括&#xff08;Contains&#xff09;&#xff1a;響應內容包括需要匹配的內容即代表響應成功&#xff0c;支持正則表達式 匹配&#xff08;Matches&#xff09;&#xff1a;響應內容要完全匹配需要匹配的內容即代表響應成功&#xff0c;大小寫不敏感&#xff0c;支持正則表達…

vue html2canvas生成base64圖片和圖片高度

vue html2canvas生成圖片 exportAsBase64() {const ele document.getElementById(content);html2canvas(ele, {dpi: 96, // 分辨率 scale: 2, // 設置縮放 useCORS: true, // 允許canvas畫布內跨域請求外部鏈接圖片 bgcolor: #ffffff, // 背景顏色 logging: false, // 不…

rust之cargo install cargo-binstall 是什么

cargo-binstall 是什么 官方&#xff1a;https://lib.rs/crates/cargo-binstall Binstall 提供了一種低復雜性的機制來安裝 Rust 二進制文件&#xff0c;作為從源代碼&#xff08;通過 cargo install &#xff09;構建或手動下載軟件包的替代方案。這旨在與現有的 CI 工件和基…

Windows安裝ElasticSearch版本7.17.0

在Windows系統上本地安裝Elasticsearch的詳細步驟如下&#xff1a; 1. 下載Elasticsearch 訪問 Elasticsearch下載頁面。選擇適用于Windows的版本7.17.0&#xff0c;并下載ZIP文件。 2. 解壓文件 下載完成后&#xff0c;找到ZIP文件&#xff08;例如 elasticsearch-7.17.0.…

【算法篇】冒泡排序算法JavaScript版

冒泡排序算法&#xff1a;原理與實現 冒泡排序&#xff08;Bubble Sort&#xff09;是一種簡單的排序算法&#xff0c;它重復地遍歷要排序的數列&#xff0c;一次比較兩個元素&#xff0c;如果它們的順序錯誤就把它們交換過來。遍歷數列的工作是重復地進行直到沒有再需要交換&…

spoon基礎使用-第一個轉換文件

新建一個轉換&#xff0c;文件->新建->轉換&#xff0c;也可以直接ctralN新建。 從右邊主對象樹拖拽一個輸入->表輸入&#xff1b;輸出->文本文檔輸出&#xff1b;也可以直接在搜索框搜素表輸入、文本文檔輸出。 雙擊表輸入新建一個數據庫連接 確定后就可以在S…

【人工智能】第二部分:ChatGPT的架構設計和訓練過程

人不走空 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌賦&#xff1a;斯是陋室&#xff0c;惟吾德馨 目錄 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌…