From 7dc28b23ab97471f281aef407b600cb75fbc5e1c Mon Sep 17 00:00:00 2001 From: x_ying <2013301500044@whu.edu.cn> Date: Thu, 29 Sep 2022 11:08:53 +0800 Subject: [PATCH] OpenEuler EaseSearch System codes --- EaseSearch/.gitignore | 33 ++ EaseSearch/.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 58727 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + EaseSearch/Dockerfile | 20 + EaseSearch/LICENSE | 127 +++++ EaseSearch/README.md | 0 EaseSearch/mvnw | 316 ++++++++++++ EaseSearch/mvnw.cmd | 188 ++++++++ EaseSearch/pom.xml | 118 +++++ EaseSearch/src/main/java/META-INF/MANIFEST.MF | 3 + .../docsearch/DocSearchApplication.java | 15 + .../docsearch/config/ElasticSearchConfig.java | 80 ++++ .../com/search/docsearch/config/MySystem.java | 22 + .../search/docsearch/config/SystemConfig.java | 52 ++ .../search/docsearch/config/TipSystem.java | 22 + .../docsearch/config/TipSystemConfig.java | 52 ++ .../search/docsearch/constant/Constants.java | 8 + .../search/docsearch/controller/BeginFun.java | 63 +++ .../controller/DivideController.java | 75 +++ .../controller/SearchController.java | 165 +++++++ .../com/search/docsearch/entity/Article.java | 48 ++ .../docsearch/entity/vo/SearchCondition.java | 24 + .../docsearch/entity/vo/SearchTags.java | 26 + .../search/docsearch/entity/vo/Suggest.java | 6 + .../search/docsearch/entity/vo/SysResult.java | 55 +++ .../docsearch/service/DivideService.java | 10 + .../docsearch/service/SearchService.java | 41 ++ .../service/impl/DivideServiceImpl.java | 101 ++++ .../service/impl/SearchServiceImpl.java | 450 ++++++++++++++++++ .../search/docsearch/utils/EulerParse.java | 144 ++++++ .../com/search/docsearch/utils/IdUtil.java | 9 + .../com/search/docsearch/utils/commonUse.java | 37 ++ EaseSearch/src/main/resources/application.yml | 17 + .../src/main/resources/mapping/mapping.json | 94 ++++ .../main/resources/mapping/tips_mapping.json | 36 ++ .../resources/script/mindspore/initDoc.sh | 44 ++ .../resources/script/openeuler/initDoc.sh | 88 ++++ .../resources/script/openeuler/updateDoc.sh | 63 +++ .../resources/script/opengauss/initDoc.sh | 52 ++ .../resources/script/opengauss/updateDoc.sh | 0 .../docsearch/DocSearchApplicationTests.java | 79 +++ 41 files changed, 2785 insertions(+) create mode 100644 EaseSearch/.gitignore create mode 100644 EaseSearch/.mvn/wrapper/maven-wrapper.jar create mode 100644 EaseSearch/.mvn/wrapper/maven-wrapper.properties create mode 100644 EaseSearch/Dockerfile create mode 100644 EaseSearch/LICENSE create mode 100644 EaseSearch/README.md create mode 100644 EaseSearch/mvnw create mode 100644 EaseSearch/mvnw.cmd create mode 100644 EaseSearch/pom.xml create mode 100644 EaseSearch/src/main/java/META-INF/MANIFEST.MF create mode 100644 EaseSearch/src/main/java/com/search/docsearch/DocSearchApplication.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/config/ElasticSearchConfig.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/config/MySystem.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/config/SystemConfig.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/config/TipSystem.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/config/TipSystemConfig.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/constant/Constants.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/controller/BeginFun.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/controller/DivideController.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/controller/SearchController.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/entity/Article.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchCondition.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchTags.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/entity/vo/Suggest.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/entity/vo/SysResult.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/service/DivideService.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/service/SearchService.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/service/impl/DivideServiceImpl.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/service/impl/SearchServiceImpl.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/utils/EulerParse.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/utils/IdUtil.java create mode 100644 EaseSearch/src/main/java/com/search/docsearch/utils/commonUse.java create mode 100644 EaseSearch/src/main/resources/application.yml create mode 100644 EaseSearch/src/main/resources/mapping/mapping.json create mode 100644 EaseSearch/src/main/resources/mapping/tips_mapping.json create mode 100644 EaseSearch/src/main/resources/script/mindspore/initDoc.sh create mode 100644 EaseSearch/src/main/resources/script/openeuler/initDoc.sh create mode 100644 EaseSearch/src/main/resources/script/openeuler/updateDoc.sh create mode 100644 EaseSearch/src/main/resources/script/opengauss/initDoc.sh create mode 100644 EaseSearch/src/main/resources/script/opengauss/updateDoc.sh create mode 100644 EaseSearch/src/test/java/com/search/docsearch/DocSearchApplicationTests.java diff --git a/EaseSearch/.gitignore b/EaseSearch/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/EaseSearch/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/EaseSearch/.mvn/wrapper/maven-wrapper.jar b/EaseSearch/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..c1dd12f17644411d6e840bd5a10c6ecda0175f18 GIT binary patch literal 58727 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%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| literal 0 HcmV?d00001 diff --git a/EaseSearch/.mvn/wrapper/maven-wrapper.properties b/EaseSearch/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..22f219d --- /dev/null +++ b/EaseSearch/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/EaseSearch/Dockerfile b/EaseSearch/Dockerfile new file mode 100644 index 0000000..bab5c7d --- /dev/null +++ b/EaseSearch/Dockerfile @@ -0,0 +1,20 @@ +FROM node + +ENV LANG C.UTF-8 +ENV LC_ALL C.UTF-8 +ENV LANGUAGE C.UTF-8 +ENV NODE_OPTIONS --max-old-space-size=8192 + +RUN mkdir -p /EaseSearch \ + && apt update \ + && apt-get install -y openjdk-17-jdk + +WORKDIR /EaseSearch +COPY . /EaseSearch +RUN chmod 777 -R ./* \ + && ./mvnw clean install package -Dmaven.test.skip \ + && cd ./target/classes \ + && chmod 777 -R script \ + && cd ../ +EXPOSE 8080 +CMD java -jar ./target/EaseSearch-0.0.1-SNAPSHOT.jar diff --git a/EaseSearch/LICENSE b/EaseSearch/LICENSE new file mode 100644 index 0000000..9e32cde --- /dev/null +++ b/EaseSearch/LICENSE @@ -0,0 +1,127 @@ + 木兰宽松许可证, 第2版 + + 木兰宽松许可证, 第2版 + 2020年1月 http://license.coscl.org.cn/MulanPSL2 + + + 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + + 0. 定义 + + “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + + “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + + “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + + “法人实体”是指提交贡献的机构及其“关联实体”。 + + “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + + 1. 授予版权许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + + 2. 授予专利许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + + 3. 无商标许可 + + “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + + 4. 分发限制 + + 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + + 5. 免责声明与责任限制 + + “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + + 6. 语言 + “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + + 条款结束 + + 如何将木兰宽松许可证,第2版,应用到您的软件 + + 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + + 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + + 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + + 3, 请将如下声明文本放入每个源文件的头部注释中。 + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. + + + Mulan Permissive Software License,Version 2 + + Mulan Permissive Software License,Version 2 (Mulan PSL v2) + January 2020 http://license.coscl.org.cn/MulanPSL2 + + Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + + 0. Definition + + Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + + Contribution means the copyrightable work licensed by a particular Contributor under this License. + + Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + + Legal Entity means the entity making a Contribution and all its Affiliates. + + Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + + 1. Grant of Copyright License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + + 2. Grant of Patent License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + + 3. No Trademark License + + No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + + 4. Distribution Restriction + + You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + + 5. Disclaimer of Warranty and Limitation of Liability + + THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 6. Language + + THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + + END OF THE TERMS AND CONDITIONS + + How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + + To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + + i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + + ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. diff --git a/EaseSearch/README.md b/EaseSearch/README.md new file mode 100644 index 0000000..e69de29 diff --git a/EaseSearch/mvnw b/EaseSearch/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/EaseSearch/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/EaseSearch/mvnw.cmd b/EaseSearch/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/EaseSearch/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/EaseSearch/pom.xml b/EaseSearch/pom.xml new file mode 100644 index 0000000..5e62676 --- /dev/null +++ b/EaseSearch/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.1 + + + + com.search + EaseSearch + 0.0.1-SNAPSHOT + EaseSearch + Demo project for Spring Boot + + 17 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + + + org.elasticsearch + elasticsearch + 7.6.2 + + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 7.6.2 + + + + com.alibaba + fastjson + 2.0.7 + + + + org.projectlombok + lombok + true + + + + commons-io + commons-io + 2.6 + + + + org.commonmark + commonmark + 0.18.1 + + + org.commonmark + commonmark-ext-gfm-tables + 0.18.1 + + + + org.jsoup + jsoup + 1.13.1 + + + + + org.yaml + snakeyaml + 1.26 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + 18 + 18 + + + + + + diff --git a/EaseSearch/src/main/java/META-INF/MANIFEST.MF b/EaseSearch/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..0896965 --- /dev/null +++ b/EaseSearch/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: com.search.docsearch.DocSearchApplication + diff --git a/EaseSearch/src/main/java/com/search/docsearch/DocSearchApplication.java b/EaseSearch/src/main/java/com/search/docsearch/DocSearchApplication.java new file mode 100644 index 0000000..7df7e2e --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/DocSearchApplication.java @@ -0,0 +1,15 @@ +package com.search.docsearch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class DocSearchApplication { + + public static void main(String[] args) { + SpringApplication.run(DocSearchApplication.class, args); + } + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/config/ElasticSearchConfig.java b/EaseSearch/src/main/java/com/search/docsearch/config/ElasticSearchConfig.java new file mode 100644 index 0000000..6e93f0c --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/config/ElasticSearchConfig.java @@ -0,0 +1,80 @@ +package com.search.docsearch.config; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.TrustStrategy; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.net.ssl.*; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +@Configuration +@EnableConfigurationProperties(ElasticsearchProperties.class) +@Slf4j +public class ElasticSearchConfig { + + @Value("${elasticsearch.username}") + private String userName; + + @Value("${elasticsearch.password}") + private String password; + + @Value("${elasticsearch.host}") + private String host; + + @Value("${elasticsearch.port}") + private int port; + + + @Bean(destroyMethod = "close") + public RestHighLevelClient restHighLevelClient() { + + RestHighLevelClient restClient = null; + try { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password)); + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + return true; + } + }).build(); + SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE); + restClient = new RestHighLevelClient( + RestClient.builder(new HttpHost(host, port, "https")).setHttpClientConfigCallback( + new RestClientBuilder.HttpClientConfigCallback() { + @Override + public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) { + httpAsyncClientBuilder.disableAuthCaching(); + httpAsyncClientBuilder.setSSLStrategy(sessionStrategy); + httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + return httpAsyncClientBuilder; + } + } + ) + ); + } catch (Exception e) { + log.error("elasticsearch TransportClient create error!!", e); + } + return restClient; + + + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/config/MySystem.java b/EaseSearch/src/main/java/com/search/docsearch/config/MySystem.java new file mode 100644 index 0000000..1af2b8e --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/config/MySystem.java @@ -0,0 +1,22 @@ +package com.search.docsearch.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class MySystem { + + public String system; + public String docsVersion; + public String index; + public String mappingPath; + public String basePath; + public String initDoc; + public String updateDoc; + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/config/SystemConfig.java b/EaseSearch/src/main/java/com/search/docsearch/config/SystemConfig.java new file mode 100644 index 0000000..0dc405f --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/config/SystemConfig.java @@ -0,0 +1,52 @@ +package com.search.docsearch.config; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Locale; + +@Configuration +@EnableConfigurationProperties(ElasticsearchProperties.class) +@Slf4j +public class SystemConfig { + + @Value("${system}") + private String system; + @Value("${docsversion}") + private String docsVersion; + @Value("${dep}") + private String dep; + + + public static final String MAPPINGPATH = "/EaseSearch/target/classes/mapping/mapping.json"; + + public static final String BASEPATH = "/usr/local/docs/target/"; + + @Bean + public MySystem setConfig() { + system = system.toLowerCase(Locale.ROOT); + dep = dep.toLowerCase(Locale.ROOT); + MySystem mySystem = new MySystem(); + + mySystem.setSystem(system); + + if (dep.equals("test")) { + mySystem.setIndex(system + "_articles_test"); + } else { + mySystem.setIndex(system + "_articles"); + } + + mySystem.setDocsVersion(docsVersion); + mySystem.setMappingPath(MAPPINGPATH); + mySystem.setBasePath(BASEPATH); + + mySystem.setInitDoc("/EaseSearch/target/classes/script/" + system + "/initDoc.sh"); + mySystem.setUpdateDoc("/EaseSearch/target/classes/script/" + system + "/updateDoc.sh"); + return mySystem; + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/config/TipSystem.java b/EaseSearch/src/main/java/com/search/docsearch/config/TipSystem.java new file mode 100644 index 0000000..7cdb771 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/config/TipSystem.java @@ -0,0 +1,22 @@ +package com.search.docsearch.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class TipSystem { + + public String system; + public String docsVersion; + public String index; + public String mappingPath; + public String basePath; + public String initDoc; + public String updateDoc; + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/config/TipSystemConfig.java b/EaseSearch/src/main/java/com/search/docsearch/config/TipSystemConfig.java new file mode 100644 index 0000000..734eb40 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/config/TipSystemConfig.java @@ -0,0 +1,52 @@ +package com.search.docsearch.config; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Locale; + +@Configuration +@EnableConfigurationProperties(ElasticsearchProperties.class) +@Slf4j +public class TipSystemConfig { + + @Value("${system}") + private String system; + @Value("${docsversion}") + private String docsVersion; + @Value("${dep}") + private String dep; + + + public static final String TIPMAPPINGPATH = TipSystemConfig.class.getClassLoader().getResource("").getPath()+ "mapping/tips_mapping.json"; + + public static final String TIPBASEPATH = "/usr/local/docs/target/"; + + @Bean + public TipSystem setTipConfig() { + system = system.toLowerCase(Locale.ROOT); + dep = dep.toLowerCase(Locale.ROOT); + TipSystem tipSystem = new TipSystem(); + + tipSystem.setSystem(system); + + if (dep.equals("test")) { + tipSystem.setIndex(system + "_tips_test"); + } else { + tipSystem.setIndex(system + "_tips"); + } + + tipSystem.setDocsVersion(docsVersion); + tipSystem.setMappingPath(TIPMAPPINGPATH); + tipSystem.setBasePath(TIPBASEPATH); + + tipSystem.setInitDoc("/EaseSearch/target/classes/script/" + system + "/initDoc.sh"); + tipSystem.setUpdateDoc("/EaseSearch/target/classes/script/" + system + "/updateDoc.sh"); + return tipSystem; + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/constant/Constants.java b/EaseSearch/src/main/java/com/search/docsearch/constant/Constants.java new file mode 100644 index 0000000..2749e80 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/constant/Constants.java @@ -0,0 +1,8 @@ +package com.search.docsearch.constant; + +public class Constants { + public static final String BASEPATH = "/usr/local/docs/target/"; +} + + + diff --git a/EaseSearch/src/main/java/com/search/docsearch/controller/BeginFun.java b/EaseSearch/src/main/java/com/search/docsearch/controller/BeginFun.java new file mode 100644 index 0000000..9e95343 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/controller/BeginFun.java @@ -0,0 +1,63 @@ +package com.search.docsearch.controller; + + +import com.search.docsearch.config.MySystem; +import com.search.docsearch.service.SearchService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +@Component +@Slf4j +@RestController +public class BeginFun implements ApplicationRunner { + @Autowired + public SearchService searchService; + @Autowired + @Qualifier("setConfig") + private MySystem s; + + + @Override + @PostMapping("begin") + public void run(ApplicationArguments args) throws IOException { + boolean success = false; + try { + log.info("===============开始拉取仓库资源================="); + ProcessBuilder pb = new ProcessBuilder(s.initDoc); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line = null; + while ((line = reader.readLine()) != null) + { + log.info(line); + if (line.contains("build complete in")) { + log.info("Static resource build successfully"); + success = true; + } + } + System.out.println("---"); + log.info("===============仓库资源拉取成功================="); + } catch (Exception e) { + log.error(e.getMessage()); + } + System.out.println("ddd"); + if (success) { + searchService.refreshDoc(); + } else { + log.info("初始化数据失败,查看日志!"); + } + + } + + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/controller/DivideController.java b/EaseSearch/src/main/java/com/search/docsearch/controller/DivideController.java new file mode 100644 index 0000000..e905de8 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/controller/DivideController.java @@ -0,0 +1,75 @@ +package com.search.docsearch.controller; + + +import com.search.docsearch.entity.vo.SysResult; +import com.search.docsearch.service.DivideService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@Slf4j +@RequestMapping("/search/sort") +public class DivideController { + @Autowired + private DivideService divideService; + + + + @PostMapping("blog") + public SysResult DivideBLog(@RequestBody Map m){ + + try { + Map result = divideService.advancedSearch(m, "blog"); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + e.printStackTrace(); + } + + + return SysResult.fail("查询失败", null); + } + + + @PostMapping("news") + public SysResult DivideNews(@RequestBody Map m){ + try { + Map result = divideService.advancedSearch(m, "news"); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + e.printStackTrace(); + } + + + return SysResult.fail("查询失败", null); + } + + @PostMapping("showcase") + public SysResult DivideShowcase(@RequestBody Map m){ + try { + Map result = divideService.advancedSearch(m, "showcase"); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + e.printStackTrace(); + } + + + return SysResult.fail("查询失败", null); + } + + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/controller/SearchController.java b/EaseSearch/src/main/java/com/search/docsearch/controller/SearchController.java new file mode 100644 index 0000000..f770e94 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/controller/SearchController.java @@ -0,0 +1,165 @@ +package com.search.docsearch.controller; + + +import com.search.docsearch.config.MySystem; +import com.search.docsearch.entity.vo.SearchCondition; +import com.search.docsearch.entity.vo.SearchTags; +import com.search.docsearch.entity.vo.SysResult; +import com.search.docsearch.service.SearchService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; + +@RestController +@Slf4j +@RequestMapping("/search") +public class SearchController { + + @Autowired + private SearchService searchService; + @Autowired + @Qualifier("setConfig") + private MySystem s; + + /** + * 查询文档 + * + * @param condition 封装查询条件 + * @return 搜索结果 + */ + @PostMapping("docs") + public SysResult searchDocByKeyword(@RequestBody SearchCondition condition) { + if (!StringUtils.hasText(condition.getKeyword())) { + return SysResult.fail("keyword must not null", null); + } +// condition.setKeyword(condition.getKeyword().replace("#", "")); + try { + Map result = searchService.searchByCondition(condition); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + return SysResult.fail("查询失败", null); + } + + + @PostMapping("count") + public SysResult getCount(@RequestBody SearchCondition condition) { + try { + Map result = searchService.getCount(condition.getKeyword(), condition.getLang()); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + return SysResult.fail("查询失败", null); + } + + @PostMapping("pop") + public SysResult getPop(String lang) { + try { + String[] result = null; + if (lang.equals("zh")) { + result = new String[] {"迁移", "docker", "mysql", "yum", "建设", "ssh", "生命周期", "虚拟化"}; + } else { + result = new String[] {"docker", "mysql", "yum", "openstack", "cla"}; + } + + return SysResult.ok("查询成功", result); + } catch (Exception e) { + log.error(e.getMessage()); + e.printStackTrace(); + } + return SysResult.fail("查询失败", null); + } + + + @PostMapping("sort") + public SysResult makeSort(@RequestBody Map m) { + + try { + Map result = searchService.advancedSearch(m); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + e.printStackTrace(); + } + + + return SysResult.fail("查询失败", null); + } + + @PostMapping("tags") + public SysResult getTags(@RequestBody SearchTags searchTags) { + try { + Map result = searchService.getTags(searchTags); + if (result == null) { + return SysResult.fail("内容不存在", null); + } + return SysResult.ok("查询成功", result); + } catch (Exception e) { + e.printStackTrace(); + } + + + return SysResult.fail("查询失败", null); + } + + + /** + * 定时任务 + */ + @Scheduled(cron = "${scheduled.cron}") + public String scheduledTask() throws IOException { + boolean success = false; + Process process; + try { + log.info("===============开始更新仓库资源================="); + ProcessBuilder pb = new ProcessBuilder(s.updateDoc); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line = null; + while ((line = reader.readLine()) != null) + { + log.info(line); + if (line.contains("build complete in")) { + success = true; + } + } + log.info("===============仓库资源更新成功================="); + } catch (IOException e) { + log.error(e.getMessage()); + } + + if (success) { + searchService.refreshDoc(); + } else { + log.info("更新数据失败,查看日志"); + } + + //每天更新联想词库中的数据 +// searchService.refreshTip(); + + return "success"; + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/entity/Article.java b/EaseSearch/src/main/java/com/search/docsearch/entity/Article.java new file mode 100644 index 0000000..b380868 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/entity/Article.java @@ -0,0 +1,48 @@ +package com.search.docsearch.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class Article { + + private static final long serialVersionUID = 1L; + private String id; + /** + * 文件全路径 + */ + private String articleName; + /** + * 页面访问路径 + */ + private String path; + /** + * 文件内容 + */ + private String textContent; + /** + * 文件名称 + */ + private String title; + /** + * 文件类型 + */ + private String type; + + /** + * 语言 + */ + private String lang; + + /** + * 版本 + */ + private String version; + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchCondition.java b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchCondition.java new file mode 100644 index 0000000..f690c9f --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchCondition.java @@ -0,0 +1,24 @@ +package com.search.docsearch.entity.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class SearchCondition implements Serializable { + + @Serial + private static final long serialVersionUID = -969897369024720352L; + private String lang; + private int page = 1; + private int pageSize = 10; + private String keyword; + private String type; +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchTags.java b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchTags.java new file mode 100644 index 0000000..ec0d7bb --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SearchTags.java @@ -0,0 +1,26 @@ +package com.search.docsearch.entity.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class SearchTags implements Serializable { + @Serial + private static final long serialVersionUID = -969897369024720352L; + private String lang; + private String category; + private String want; + private Map condition; + +} + + diff --git a/EaseSearch/src/main/java/com/search/docsearch/entity/vo/Suggest.java b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/Suggest.java new file mode 100644 index 0000000..fb041d8 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/Suggest.java @@ -0,0 +1,6 @@ +package com.search.docsearch.entity.vo; + +public class Suggest { + boolean trigger; + String newKeyword; +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SysResult.java b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SysResult.java new file mode 100644 index 0000000..3a6ed67 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/entity/vo/SysResult.java @@ -0,0 +1,55 @@ +package com.search.docsearch.entity.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Accessors(chain = true) +public class SysResult implements Serializable { + + @Serial + private static final long serialVersionUID = 3208248423120492873L; + private Integer status; + private String msg; + private Object obj; + + public SysResult(Integer status, String msg, Object obj) { + this.status = status; + this.msg = msg; + this.obj = obj; + } + + public SysResult() { + } + + public SysResult(Throwable e) { + this.status = 201; + this.msg = e.getMessage(); + } + + //定义成功的静态方法 + public static SysResult ok(String msg, Object obj) { + return new SysResult(200, msg, obj); + } + + //表示定义成功的静态方法 + public static SysResult ok() { + return new SysResult(200, null, null); + } + + public static SysResult ok(Object data) { + return new SysResult(200, null, data); + } + + //定义一个失败的静态方法 + public static SysResult fail(String msg, Object data) { + return new SysResult(201, msg, data); + } + + public static SysResult fail() { + return new SysResult(201, null, null); + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/service/DivideService.java b/EaseSearch/src/main/java/com/search/docsearch/service/DivideService.java new file mode 100644 index 0000000..01d6cce --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/service/DivideService.java @@ -0,0 +1,10 @@ +package com.search.docsearch.service; + +import java.util.Map; + +public interface DivideService { + + Map advancedSearch(Map search, String category) throws Exception; + + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/service/SearchService.java b/EaseSearch/src/main/java/com/search/docsearch/service/SearchService.java new file mode 100644 index 0000000..413b708 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/service/SearchService.java @@ -0,0 +1,41 @@ +package com.search.docsearch.service; + +import com.search.docsearch.entity.vo.SearchCondition; +import com.search.docsearch.entity.vo.SearchTags; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface SearchService { + + + /** + * 根据索引名称和版本刷新数据 + * + */ + void refreshDoc() throws IOException; + + void refreshTip() throws IOException; + + + /** + * 根据条件搜索 + * + * @param condition 搜索条件 + * @return 符合条件记录 + * @throws IOException + */ + Map searchByCondition(SearchCondition condition) throws IOException; + + + Map getCount(String keyword, String lang) throws IOException; + + + Map advancedSearch(Map search) throws Exception; + + Map getTags(SearchTags searchTags) throws Exception; + + Set getSearchSuggest(Integer pageSize, String key); +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/service/impl/DivideServiceImpl.java b/EaseSearch/src/main/java/com/search/docsearch/service/impl/DivideServiceImpl.java new file mode 100644 index 0000000..27988f6 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/service/impl/DivideServiceImpl.java @@ -0,0 +1,101 @@ +package com.search.docsearch.service.impl; + +import com.search.docsearch.config.MySystem; +import com.search.docsearch.service.DivideService; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.sort.SortOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +@Service +@Slf4j +public class DivideServiceImpl implements DivideService { + + @Autowired + @Qualifier("restHighLevelClient") + private RestHighLevelClient restHighLevelClient; + + @Autowired + @Qualifier("setConfig") + private MySystem s; + + + @Override + public Map advancedSearch(Map search, String category) throws Exception { + SearchRequest request = new SearchRequest(s.index); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.filter(QueryBuilders.termQuery("category" + ".keyword", category)); + + + int page = 1; + int pageSize = 10; + String keyword = ""; + + for (Map.Entry entry : search.entrySet()) { + if (entry.getKey().equals("page")) { + page = Integer.parseInt(entry.getValue()); + continue; + } + if (entry.getKey().equals("pageSize")) { + pageSize = Integer.parseInt(entry.getValue()); + continue; + } + if (entry.getKey().equals("keyword")) { + keyword = entry.getValue(); + continue; + } + + boolQueryBuilder.filter(QueryBuilders.termQuery(entry.getKey() + ".keyword", entry.getValue())); + } + + int startIndex = (page - 1) * pageSize; + + if (!keyword.equals("")) { + MatchQueryBuilder titleMP = QueryBuilders.matchQuery("title", keyword); + titleMP.boost(2); + MatchQueryBuilder textContentMP = QueryBuilders.matchQuery("textContent", keyword); + textContentMP.boost(1); + boolQueryBuilder.should(titleMP).should(textContentMP); + + boolQueryBuilder.minimumShouldMatch(1); + } + + sourceBuilder.from(startIndex).size(pageSize); + sourceBuilder.query(boolQueryBuilder); + + sourceBuilder.sort("date", SortOrder.DESC); + + request.source(sourceBuilder); + + + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + + Map result = new HashMap<>(); + List> data = new ArrayList<>(); + for (SearchHit hit : response.getHits().getHits()) { + Map map = hit.getSourceAsMap(); + + data.add(map); + } + result.put("page", page); + result.put("pageSize", pageSize); + result.put("count", response.getHits().getTotalHits().value); + result.put("records", data); + return result; + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/service/impl/SearchServiceImpl.java b/EaseSearch/src/main/java/com/search/docsearch/service/impl/SearchServiceImpl.java new file mode 100644 index 0000000..36d38c2 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/service/impl/SearchServiceImpl.java @@ -0,0 +1,450 @@ +package com.search.docsearch.service.impl; + +import com.search.docsearch.config.MySystem; +import com.search.docsearch.config.TipSystem; +import com.search.docsearch.entity.Article; +import com.search.docsearch.entity.vo.SearchCondition; +import com.search.docsearch.entity.vo.SearchTags; +import com.search.docsearch.entity.vo.Suggest; +import com.search.docsearch.service.SearchService; +import com.search.docsearch.utils.EulerParse; +import com.search.docsearch.utils.IdUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.GetIndexRequest; +import org.elasticsearch.common.unit.Fuzziness; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.*; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.BucketOrder; +import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; +import org.elasticsearch.search.sort.ScoreSortBuilder; +import org.elasticsearch.search.sort.SortBuilder; +import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.search.suggest.SuggestBuilder; +import org.elasticsearch.search.suggest.SuggestBuilders; +import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; + + +@Service +@Slf4j +public class SearchServiceImpl implements SearchService { + + @Autowired + @Qualifier("restHighLevelClient") + private RestHighLevelClient restHighLevelClient; + + @Autowired + @Qualifier("setConfig") + private MySystem s; + + @Autowired + @Qualifier("setTipConfig") + private TipSystem ts; + + + @Override + public void refreshDoc() throws IOException { + + GetIndexRequest request = new GetIndexRequest(s.index); + request.local(false); + request.humanReadable(true); + request.includeDefaults(false); + boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); + if (!exists) { + CreateIndexRequest request1 = new CreateIndexRequest(s.index); + File mappingJson = FileUtils.getFile(s.mappingPath); + String mapping = FileUtils.readFileToString(mappingJson, StandardCharsets.UTF_8); + + request1.mapping(mapping, XContentType.JSON); + request1.setTimeout(TimeValue.timeValueMillis(1)); + + restHighLevelClient.indices().create(request1, RequestOptions.DEFAULT); + } + + File indexFile = new File(s.basePath); + if (!indexFile.exists()) { + log.error(String.format("%s 文件夹不存在", indexFile.getPath())); + log.error("服务器开小差了"); + return; + } + log.info("开始更新es文档"); + String lang = ""; + String deleteType = ""; + File[] typeDir; + File[] languageDir = indexFile.listFiles(); + assert languageDir != null; + for (File languageFile : languageDir) { + lang = languageFile.getName(); + typeDir = languageFile.listFiles(); + assert typeDir != null; + for (File typeFile : typeDir) { + if (typeFile.isDirectory()) { + BulkRequest bulkRequest = new BulkRequest(); + deleteType = typeFile.getName(); + + Collection listFiles = FileUtils.listFiles(typeFile, new String[]{"md", "html"}, true); + + for (File mdFile : listFiles) { + if (!mdFile.getName().startsWith("_")) { + try { + Map map = EulerParse.parse(lang, deleteType, mdFile); + if (map != null) { + IndexRequest indexRequest = new IndexRequest(s.index).id(IdUtil.getId()).source(map); + bulkRequest.add(indexRequest); + } + } catch (Exception e) { + log.info(mdFile.getPath()); + log.error(e.getMessage()); + } + } + } + log.info(deleteType + " have " + bulkRequest.requests().size()); + DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(s.index); + BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); + boolQueryBuilder.must(new TermQueryBuilder("lang.keyword", lang)); + boolQueryBuilder.must(new TermQueryBuilder("deleteType.keyword", deleteType)); + deleteByQueryRequest.setQuery(boolQueryBuilder); + BulkByScrollResponse r = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT); + if (bulkRequest.requests().size() > 0) { + BulkResponse q = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); + log.info("wrong ? " + q.hasFailures()); + log.info(lang + "/" + deleteType + "更新成功"); + } + + } + } + } + log.info("所有文档更新成功"); + } + + + @Override + public void refreshTip() throws IOException { + GetIndexRequest request = new GetIndexRequest(ts.index); + request.local(false); + request.humanReadable(true); + request.includeDefaults(false); + boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); + +// 如果索引库不存在,按照mapping构建索引库 + if (!exists) { + CreateIndexRequest request1 = new CreateIndexRequest(ts.index); + File mappingJson = FileUtils.getFile(ts.mappingPath); + String mapping = FileUtils.readFileToString(mappingJson, StandardCharsets.UTF_8); + + request1.mapping(mapping, XContentType.JSON); + request1.setTimeout(TimeValue.timeValueMillis(1)); + + restHighLevelClient.indices().create(request1, RequestOptions.DEFAULT); + } + + //TODO:将联想词汇录入词库 + + } + + + @Override + public Map searchByCondition(SearchCondition condition) throws IOException { + + int startIndex = (condition.getPage() - 1) * condition.getPageSize(); + SearchRequest request = new SearchRequest(s.index); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + + if (StringUtils.hasText(condition.getLang())) { + boolQueryBuilder.filter(QueryBuilders.termQuery("lang.keyword", condition.getLang())); + } + if (StringUtils.hasText(condition.getType())) { + boolQueryBuilder.filter(QueryBuilders.termQuery("type.keyword", condition.getType())); + } + + MatchPhraseQueryBuilder ptitleMP = QueryBuilders.matchPhraseQuery("title", condition.getKeyword()); + ptitleMP.boost(200); + MatchPhraseQueryBuilder ptextContentMP = QueryBuilders.matchPhraseQuery("textContent", condition.getKeyword()); + ptextContentMP.boost(100); + + boolQueryBuilder.should(ptitleMP).should(ptextContentMP); + + MatchQueryBuilder titleMP = QueryBuilders.matchQuery("title", condition.getKeyword()); + titleMP.boost(2); + MatchQueryBuilder textContentMP = QueryBuilders.matchQuery("textContent", condition.getKeyword()); + textContentMP.boost(1); + boolQueryBuilder.should(titleMP).should(textContentMP); + + boolQueryBuilder.minimumShouldMatch(1); + + sourceBuilder.query(boolQueryBuilder); + + HighlightBuilder highlightBuilder = new HighlightBuilder() + .field("textContent") + .field("title") + .fragmentSize(100) + .preTags("") + .postTags(""); + sourceBuilder.highlighter(highlightBuilder); + sourceBuilder.from(startIndex).size(condition.getPageSize()); + sourceBuilder.timeout(TimeValue.timeValueMinutes(1L)); + request.source(sourceBuilder); + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + List
data = new ArrayList<>(); + + for (SearchHit hit : response.getHits().getHits()) { + Map map = hit.getSourceAsMap(); + String highLight = map.get("textContent").toString(); + String title = map.getOrDefault("title", "").toString(); + Map highlightFields = hit.getHighlightFields(); + if (highlightFields.containsKey("textContent")) { + highLight = highlightFields.get("textContent").getFragments()[0].toString(); + } + if (highlightFields.containsKey("title")) { + title = highlightFields.get("title").getFragments()[0].toString(); + } + Article article = new Article().setId(hit.getId()) + .setArticleName(map.get("articleName").toString()) + .setLang(map.getOrDefault("lang", "").toString()) + .setPath(map.getOrDefault("path", "").toString()) + .setTitle(title) + .setVersion(map.getOrDefault("version", "").toString()) + .setType(map.getOrDefault("type", "").toString()) + .setTextContent(highLight); + data.add(article); + } + if (data.isEmpty()) { + return null; + } + + Map result = new HashMap<>(); + result.put("page", condition.getPage()); + result.put("pageSize", condition.getPageSize()); + result.put("records", data); + return result; + } + + + + + + public Map getCount(String keyword, String lang) throws IOException { + SearchRequest request = new SearchRequest(s.index); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + + boolQueryBuilder.filter(QueryBuilders.termQuery("lang.keyword", lang)); + + MatchQueryBuilder titleMP = QueryBuilders.matchQuery("title", keyword); + titleMP.boost(2); + MatchQueryBuilder textContentMP = QueryBuilders.matchQuery("textContent", keyword); + textContentMP.boost(1); + boolQueryBuilder.should(titleMP).should(textContentMP); + boolQueryBuilder.minimumShouldMatch(1); + + sourceBuilder.query(boolQueryBuilder); + + sourceBuilder.aggregation(AggregationBuilders.terms("data").field("type.keyword")); + request.source(sourceBuilder); + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + + List> numberList = new ArrayList<>(); + Map numberMap = new HashMap<>(); + numberMap.put("doc_count", response.getHits().getTotalHits().value); + numberMap.put("key", "all"); + numberList.add(numberMap); + ParsedTerms aggregation = response.getAggregations().get("data"); + List buckets = aggregation.getBuckets(); + for (Terms.Bucket bucket : buckets) { + Map countMap = new HashMap<>(); + countMap.put("key", bucket.getKeyAsString()); + countMap.put("doc_count", bucket.getDocCount()); + numberList.add(countMap); + } + Map result = new HashMap<>(); + result.put("total", numberList); + return result; + } + + @Override + public Map advancedSearch(Map search) throws Exception { + SearchRequest request = new SearchRequest(s.index); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + + int page = 1; + int pageSize = 10; + String keyword = ""; + for (Map.Entry entry : search.entrySet()) { + if (entry.getKey().equals("page")) { + page = Integer.parseInt(entry.getValue()); + continue; + } + if (entry.getKey().equals("pageSize")) { + pageSize = Integer.parseInt(entry.getValue()); + continue; + } + if (entry.getKey().equals("keyword")) { + keyword = entry.getValue(); + continue; + } + + boolQueryBuilder.filter(QueryBuilders.termQuery(entry.getKey() + ".keyword", entry.getValue())); + } + + int startIndex = (page - 1) * pageSize; + + if (!keyword.equals("")) { + MatchQueryBuilder titleMP = QueryBuilders.matchQuery("title", keyword); + titleMP.boost(2); + MatchQueryBuilder textContentMP = QueryBuilders.matchQuery("textContent", keyword); + textContentMP.boost(1); + boolQueryBuilder.should(titleMP).should(textContentMP); + + boolQueryBuilder.minimumShouldMatch(1); + } + sourceBuilder.from(startIndex).size(pageSize); + sourceBuilder.query(boolQueryBuilder); + + sourceBuilder.sort("date", SortOrder.DESC); + + request.source(sourceBuilder); + + + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + + Map result = new HashMap<>(); + List> data = new ArrayList<>(); + for (SearchHit hit : response.getHits().getHits()) { + Map map = hit.getSourceAsMap(); + + data.add(map); + } + result.put("page", page); + result.put("pageSize", pageSize); + result.put("count", response.getHits().getTotalHits().value); + result.put("records", data); + return result; + } + + @Override + public Map getTags(SearchTags searchTags) throws Exception { + SearchRequest request = new SearchRequest(s.index); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.filter(QueryBuilders.termQuery("lang.keyword", searchTags.getLang())); + boolQueryBuilder.filter(QueryBuilders.termQuery("category.keyword", searchTags.getCategory())); + + + if (searchTags.getCondition() != null) { + for (Map.Entry entry : searchTags.getCondition().entrySet()) { + boolQueryBuilder.filter(QueryBuilders.termQuery(entry.getKey() + ".keyword", entry.getValue())); + } + } + + + BucketOrder bucketOrder = BucketOrder.key(false); + sourceBuilder.aggregation(AggregationBuilders.terms("data").field(searchTags.getWant() + ".keyword").size(10000).order(bucketOrder)); + sourceBuilder.query(boolQueryBuilder); + request.source(sourceBuilder); + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + ParsedTerms aggregation = response.getAggregations().get("data"); + List> numberList = new ArrayList<>(); + List buckets = aggregation.getBuckets(); + for (Terms.Bucket bucket : buckets) { + + Map countMap = new HashMap<>(); + + countMap.put("key", bucket.getKeyAsString()); + countMap.put("count", bucket.getDocCount()); + numberList.add(countMap); + } + Map result = new HashMap<>(); + result.put("totalNum", numberList); + return result; + } + + + + + + + + + + public Suggest makeSuggest(String keyword) { + //定义suggest对象 + SuggestBuilder suggestBuilder = new SuggestBuilder(); + + return null; + } + + + + + + + @Override + public Set getSearchSuggest(Integer pageSize,String key){ + //定义suggest对象 + SuggestBuilder suggestBuilder = new SuggestBuilder(); + //定义本次查询名字SEARCH_INPUT = suggest,设置prefix 补齐前缀,查询个数pagesize个,skipDuplicates去除重复数据 + CompletionSuggestionBuilder suggestion = SuggestBuilders + .completionSuggestion("textTip.py").prefix(key, Fuzziness.TWO).size(pageSize).skipDuplicates(true); + + suggestBuilder.addSuggestion("py",suggestion); + SearchRequest request = new SearchRequest().indices(ts.index).source(new SearchSourceBuilder().suggest(suggestBuilder)); + //可以通过设置searchsourcebuilder来设置_source过滤字段 + SearchResponse searchResponse = null; + try { + searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT); + System.out.println(searchResponse); + } catch (IOException e) { + e.printStackTrace(); + } + + org.elasticsearch.search.suggest.Suggest suggest = searchResponse.getSuggest(); + Set keywords = null; + if (suggest != null) { + keywords = new HashSet<>(); + List> entries = suggest.getSuggestion("py").getEntries(); + for (org.elasticsearch.search.suggest.Suggest.Suggestion.Entry entry: entries) { + for (org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option option: entry.getOptions()) { + /** 最多返回9个推荐,每个长度最大为20 */ + String keyword = option.getText().string(); + if (!StringUtils.isEmpty(keyword) && keyword.length() <= 20) { + /** 去除输入字段 */ + if (keyword.equals(key)) continue; + keywords.add(keyword); + if (keywords.size() >= pageSize) { + break; + } + } + } + } + } + return keywords; + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/utils/EulerParse.java b/EaseSearch/src/main/java/com/search/docsearch/utils/EulerParse.java new file mode 100644 index 0000000..29dbd77 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/utils/EulerParse.java @@ -0,0 +1,144 @@ +package com.search.docsearch.utils; + +import com.search.docsearch.constant.Constants; + +import org.apache.commons.io.FileUtils; +import org.commonmark.node.Node; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.springframework.util.StringUtils; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class EulerParse { + + public static final String BLOGS = "blog"; + public static final String DOCS = "docs"; + public static final String NEWS = "news"; + public static final String OTHER = "other"; + public static final String MIGRATION = "migration"; + public static final String SHOWCASE = "showcase"; + + + public static Map parse(String lang, String deleteType, File mdFile) throws Exception { + String type = deleteType; + String fileName = mdFile.getName(); + String path = mdFile.getPath() + .replace("\\", "/") + .replace(Constants.BASEPATH + lang + "/", "") + .replace("\\\\", "/") + .replace(".md", "") + .replace(".html", ""); + if (!DOCS.equals(deleteType) + && !BLOGS.equals(deleteType) + && !NEWS.equals(deleteType) + && !SHOWCASE.equals(deleteType) + && !MIGRATION.equals(deleteType)) { + type = OTHER; + if(!fileName.equals("index.html")) { + return null; + } + path = path.substring(0, path.length() - 5); + } + Map jsonMap = new HashMap<>(); + jsonMap.put("lang", lang); + jsonMap.put("deleteType", deleteType); + jsonMap.put("type", type); + jsonMap.put("articleName", fileName); + jsonMap.put("path", path); + + String fileContent = FileUtils.readFileToString(mdFile, StandardCharsets.UTF_8); + + + Parser parser = Parser.builder().build(); + HtmlRenderer renderer = HtmlRenderer.builder().build(); + + if (fileName.endsWith(".html")) { + Document node = Jsoup.parse(fileContent); + Elements titles = node.getElementsByTag("title"); + if (titles.size() > 0) { + jsonMap.put("title", titles.first().text()); + } + + Elements elements = node.getElementsByTag("main"); + if (elements.size() > 0) { + Element mainNode = elements.first(); + jsonMap.put("textContent", mainNode.text()); + } + } else { + if (DOCS.equals(type)) { + Node document = parser.parse(fileContent); + Document node = Jsoup.parse(renderer.render(document)); + + if (node.getElementsByTag("h1").size() > 0) { + jsonMap.put("title", node.getElementsByTag("h1").first().text()); + } else { + jsonMap.put("title", mdFile.getName()); + } + + if (node.getElementsByTag("a").size() > 0 && node.getElementsByTag("ul").size() > 0) { + Element a = node.getElementsByTag("a").first(); + if (a.attr("href").startsWith("#")) { + node.getElementsByTag("ul").first().remove(); + } + } + jsonMap.put("textContent",node.text()); + + String version = path.replaceFirst(type + "/", ""); + version = version.substring(0, version.indexOf("/")); + + jsonMap.put("version", version); + } else { + String r = ""; + if (fileContent.contains("---")) { + fileContent = fileContent.substring(fileContent.indexOf("---") + 3); + if (fileContent.contains("---")) { + r = fileContent.substring(0, fileContent.indexOf("---")); + fileContent = fileContent.substring(fileContent.indexOf("---") + 3); + } + } + + + Node document = parser.parse(fileContent); + Document node = Jsoup.parse(renderer.render(document)); + jsonMap.put("textContent", node.text()); + + + Yaml yaml = new Yaml(); + Map ret = yaml.load(r); + + String key = ""; + Object value = ""; + for (Map.Entry entry : ret.entrySet()) { + //TODO 需要处理日期不标准导致的存入ES失败的问题。 + key = entry.getKey().toLowerCase(Locale.ROOT); + value = entry.getValue(); + if (key.equals("date")) { + String archives = value.toString().substring(0, 7); + jsonMap.put("archives", archives); + } + if (key.equals("author") && value instanceof String) { + value = new String[]{value.toString()}; + } + jsonMap.put(key, value); + } + } + } + + if (jsonMap.get("title") == "" || jsonMap.get("textContent") == "") { + return null; + } + + return jsonMap; + } + +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/utils/IdUtil.java b/EaseSearch/src/main/java/com/search/docsearch/utils/IdUtil.java new file mode 100644 index 0000000..6ccfffe --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/utils/IdUtil.java @@ -0,0 +1,9 @@ +package com.search.docsearch.utils; + +import java.util.UUID; + +public class IdUtil { + public static String getId() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } +} diff --git a/EaseSearch/src/main/java/com/search/docsearch/utils/commonUse.java b/EaseSearch/src/main/java/com/search/docsearch/utils/commonUse.java new file mode 100644 index 0000000..6e7ca98 --- /dev/null +++ b/EaseSearch/src/main/java/com/search/docsearch/utils/commonUse.java @@ -0,0 +1,37 @@ +package com.search.docsearch.utils; + +public class commonUse { + public static String getValue(String r, String t) { + String result = ""; + + for(int i = 0; i < r.length(); i ++) { + if (r.contains(t)) { + r = r.substring(r.indexOf(t) + t.length()); + if (r.substring(0, 4).contains("=")) { + result = r.substring(r.indexOf("=") + 1); + if (t.equals("tags") || t.equals("categories")) { + result = result.substring(result.indexOf("[") + 1); + result = result.substring(0, result.indexOf("]")); + result = result.replaceAll("'", ""); + break; + } else { + if (result.substring(0, 3).contains("'")) { + result = result.substring(result.indexOf("'") + 1); + result = result.substring(0, result.indexOf("'")); + } else if (result.substring(0, 3).contains("\"")){ + result = result.substring(result.indexOf("\"") + 1); + result = result.substring(0, result.indexOf("\"")); + } + break; + } + } + } else { + break; + } + } + + + return result; + } + +} diff --git a/EaseSearch/src/main/resources/application.yml b/EaseSearch/src/main/resources/application.yml new file mode 100644 index 0000000..436e920 --- /dev/null +++ b/EaseSearch/src/main/resources/application.yml @@ -0,0 +1,17 @@ +#es用户名 密码等配置 +elasticsearch: + host: ${eshost} + username: ${esusername} + password: ${espassword} + port: ${esport} + +#定时读取配置 +scheduled: + cron: 0 31 11 ? * * + +#openEuler openGauss openLookeng mindSpore +system: ${searchsystem:openEuler} +docsversion: 20 + +#formal test +dep: ${depp:test} diff --git a/EaseSearch/src/main/resources/mapping/mapping.json b/EaseSearch/src/main/resources/mapping/mapping.json new file mode 100644 index 0000000..b06260a --- /dev/null +++ b/EaseSearch/src/main/resources/mapping/mapping.json @@ -0,0 +1,94 @@ +{ + "properties": { + "_class": { + "type": "keyword", + "index": false, + "doc_values": false + }, + "articleName": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above" : 256 + } + } + }, + "lang": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "path": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "textContent": { + "type": "text", + "analyzer": "ik_max_word", + "search_analyzer": "ik_smart" + }, + "title": { + "type": "text", + "analyzer": "ik_max_word", + "search_analyzer": "ik_smart" + }, + "type": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "deleteType": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "version": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "date" : { + "type" : "date" + }, + "archives": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + } + } +} diff --git a/EaseSearch/src/main/resources/mapping/tips_mapping.json b/EaseSearch/src/main/resources/mapping/tips_mapping.json new file mode 100644 index 0000000..8127ac5 --- /dev/null +++ b/EaseSearch/src/main/resources/mapping/tips_mapping.json @@ -0,0 +1,36 @@ +{ + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above" : 256 + } + } + }, + "lang": { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "textTip": { + "type": "completion", + "analyzer": "ik_smart", + "fields": { + "kw": { + "type": "keyword" + }, + "py": { + "type": "completion", + "boost": 1, + "analyzer": "pinyin" + } + } + } + } +} \ No newline at end of file diff --git a/EaseSearch/src/main/resources/script/mindspore/initDoc.sh b/EaseSearch/src/main/resources/script/mindspore/initDoc.sh new file mode 100644 index 0000000..4bf81c1 --- /dev/null +++ b/EaseSearch/src/main/resources/script/mindspore/initDoc.sh @@ -0,0 +1,44 @@ +#!/bin/sh +if [ -d "/usr/local/docs" ]; then + rm -rf /usr/local/docs/source/* + rm -rf /usr/local/docs/target/* +fi +mkdir -p /usr/local/docs/source/ +mkdir -p /usr/local/docs/target/zh/ +mkdir -p /usr/local/docs/target/en/ + + +# shellcheck disable=SC2164 +cd /usr/local/docs/source +git clone https://gitee.com/mindspore/mindspore.github.io.git + +mkdir -p /usr/local/docs/target/zh/install/ + + + + +mkdir -p /usr/local/docs/target/zh/tutorial/ +cp -r ./webapp/public/tutorials/zh-CN/* ../target/zh/tutorial/zh-CN/ +cp -r ./webapp/public/tutorials/application/zh-CN/* ../target/zh/tutorial/application/zh-CN/ +cp -r ./webapp/public/tutorials/experts/zh-CN/* ../target/zh/tutorial/experts/zh-CN/ + + +mkdir -p /usr/local/docs/target/zh/api/ +mkdir -p /usr/local/docs/target/zh/docs/ +cp -r ./webapp/public/docs/zh-CN/* ../target/docs/zh-CN/* + + + + + + + + + +mkdir -p /usr/local/docs/target/en/install/ +mkdir -p /usr/local/docs/target/en/tutorial/ +cp -r ./webapp/public/tutorials/en/* ../target/en/tutorial/en/ +cp -r ./webapp/public/tutorials/application/en/* ../target/en/tutorial/application/en/ +cp -r ./webapp/public/tutorials/experts/en/* ../target/en/tutorial/experts/en/ +mkdir -p /usr/local/docs/target/en/api/ +mkdir -p /usr/local/docs/target/en/docs/ \ No newline at end of file diff --git a/EaseSearch/src/main/resources/script/openeuler/initDoc.sh b/EaseSearch/src/main/resources/script/openeuler/initDoc.sh new file mode 100644 index 0000000..352c895 --- /dev/null +++ b/EaseSearch/src/main/resources/script/openeuler/initDoc.sh @@ -0,0 +1,88 @@ +#!/bin/bash +if [ -d "/usr/local/docs" ]; then + rm -rf /usr/local/docs/source/* + rm -rf /usr/local/docs/target/* +fi + +npm i pnpm -g + +mkdir -p /usr/local/docs/source/ +mkdir -p /usr/local/docs/target/zh/ +mkdir -p /usr/local/docs/target/en/ +mkdir -p /usr/local/docs/target/ru/ + +# shellcheck disable=SC2164 +cd /usr/local/docs/source +git clone https://gitee.com/openeuler/openEuler-portal.git +# shellcheck disable=SC2164 +cd ./openEuler-portal +pnpm install +pnpm build + + + +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/zh /usr/local/docs/target/ +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/en /usr/local/docs/target/ +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/ru /usr/local/docs/target/ + + +rm -rf /usr/local/docs/target/zh/blog +cp -r /usr/local/docs/source/openEuler-portal/app/zh/blog /usr/local/docs/target/zh/ +rm -rf /usr/local/docs/target/zh/news +cp -r /usr/local/docs/source/openEuler-portal/app/zh/news /usr/local/docs/target/zh/ +rm -rf /usr/local/docs/target/zh/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/zh/showcase /usr/local/docs/target/zh/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/zh/showcase/index.html /usr/local/docs/target/zh/showcase/ +rm -rf /usr/local/docs/target/zh/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + + +rm -rf /usr/local/docs/target/en/blog +cp -r /usr/local/docs/source/openEuler-portal/app/en/blog /usr/local/docs/target/en/ +rm -rf /usr/local/docs/target/en/news +cp -r /usr/local/docs/source/openEuler-portal/app/en/news /usr/local/docs/target/en/ +rm -rf /usr/local/docs/target/en/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/en/showcase /usr/local/docs/target/en/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/en/showcase/index.html /usr/local/docs/target/en/showcase/ +rm -rf /usr/local/docs/target/en/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + +rm -rf /usr/local/docs/target/ru/blog +cp -r /usr/local/docs/source/openEuler-portal/app/ru/blog /usr/local/docs/target/ru/ +rm -rf /usr/local/docs/target/ru/news +cp -r /usr/local/docs/source/openEuler-portal/app/ru/news /usr/local/docs/target/ru/ +rm -rf /usr/local/docs/target/ru/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/ru/showcase /usr/local/docs/target/ru/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/ru/showcase/index.html /usr/local/docs/target/ru/showcase/ +rm -rf /usr/local/docs/target/ru/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + + +# shellcheck disable=SC2164 +cd /usr/local/docs/source + +git clone https://gitee.com/openeuler/docs.git + +# shellcheck disable=SC2164 +cd ./docs +for r in $(git branch -r --list "origin/stable2-*") +do + b=${r##*origin/stable2-} + git checkout -b $b $r + mkdir -p /usr/local/docs/target/zh/docs/$b/docs + mkdir -p /usr/local/docs/target/en/docs/$b/docs + cp -r /usr/local/docs/source/docs/docs/zh/docs/* /usr/local/docs/target/zh/docs/$b/docs/ + cp -r /usr/local/docs/source/docs/docs/en/docs/* /usr/local/docs/target/en/docs/$b/docs/ +done + + + + + + + + + + + + diff --git a/EaseSearch/src/main/resources/script/openeuler/updateDoc.sh b/EaseSearch/src/main/resources/script/openeuler/updateDoc.sh new file mode 100644 index 0000000..e87fab4 --- /dev/null +++ b/EaseSearch/src/main/resources/script/openeuler/updateDoc.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +rm -rf /usr/local/docs/target/* +mkdir -p /usr/local/docs/target/zh/ +mkdir -p /usr/local/docs/target/en/ + +# shellcheck disable=SC2164 +cd /usr/local/docs/source/openEuler-portal +git pull +pnpm install +pnpm build + + +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/zh /usr/local/docs/target/ +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/en /usr/local/docs/target/ +cp -r /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/ru /usr/local/docs/target/ + + +rm -rf /usr/local/docs/target/zh/blog +cp -r /usr/local/docs/source/openEuler-portal/app/zh/blog /usr/local/docs/target/zh/ +rm -rf /usr/local/docs/target/zh/news +cp -r /usr/local/docs/source/openEuler-portal/app/zh/news /usr/local/docs/target/zh/ +rm -rf /usr/local/docs/target/zh/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/zh/showcase /usr/local/docs/target/zh/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/zh/showcase/index.html /usr/local/docs/target/zh/showcase/ +rm -rf /usr/local/docs/target/zh/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + + +rm -rf /usr/local/docs/target/en/blog +cp -r /usr/local/docs/source/openEuler-portal/app/en/blog /usr/local/docs/target/en/ +rm -rf /usr/local/docs/target/en/news +cp -r /usr/local/docs/source/openEuler-portal/app/en/news /usr/local/docs/target/en/ +rm -rf /usr/local/docs/target/en/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/en/showcase /usr/local/docs/target/en/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/en/showcase/index.html /usr/local/docs/target/en/showcase/ +rm -rf /usr/local/docs/target/en/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + +rm -rf /usr/local/docs/target/ru/blog +cp -r /usr/local/docs/source/openEuler-portal/app/ru/blog /usr/local/docs/target/ru/ +rm -rf /usr/local/docs/target/ru/news +cp -r /usr/local/docs/source/openEuler-portal/app/ru/news /usr/local/docs/target/ru/ +rm -rf /usr/local/docs/target/ru/showcase +cp -r /usr/local/docs/source/openEuler-portal/app/ru/showcase /usr/local/docs/target/ru/ +cp /usr/local/docs/source/openEuler-portal/app/.vitepress/dist/ru/showcase/index.html /usr/local/docs/target/ru/showcase/ +rm -rf /usr/local/docs/target/ru/migration +cp -r /usr/local/docs/source/openEuler-portal/app/zh/migration /usr/local/docs/target/zh/ + + +# shellcheck disable=SC2164 +cd /usr/local/docs/source/docs +git pull +for r in $(git branch -r --list "origin/stable2-*") +do + b=${r##*origin/stable2-} + git checkout -b $b $r + git pull + mkdir -p /usr/local/docs/target/zh/docs/$b/docs + mkdir -p /usr/local/docs/target/en/docs/$b/docs + cp -r /usr/local/docs/source/docs/docs/zh/docs/* /usr/local/docs/target/zh/docs/$b/docs/ + cp -r /usr/local/docs/source/docs/docs/en/docs/* /usr/local/docs/target/en/docs/$b/docs/ +done \ No newline at end of file diff --git a/EaseSearch/src/main/resources/script/opengauss/initDoc.sh b/EaseSearch/src/main/resources/script/opengauss/initDoc.sh new file mode 100644 index 0000000..c995e7f --- /dev/null +++ b/EaseSearch/src/main/resources/script/opengauss/initDoc.sh @@ -0,0 +1,52 @@ +#!/bin/bash +if [ -d "/usr/local/docs" ]; then + rm -rf /usr/local/docs/source/* + rm -rf /usr/local/docs/target/* +fi +mkdir -p /usr/local/docs/source/ +mkdir -p /usr/local/docs/target/zh/ +mkdir -p /usr/local/docs/target/en/ + +# shellcheck disable=SC2164 +cd /usr/local/docs/source +git clone https://gitee.com/opengauss/website.git +git clone https://gitee.com/opengauss/blog.git + + +mkdir -p /usr/local/docs/target/zh/events/ +mkdir -p /usr/local/docs/target/zh/news/ +mkdir -p /usr/local/docs/target/zh/post/ +cp -r ./website/content/zh/events/* ../target/zh/events/ +cp -r ./website/content/zh/news/* ../target/zh/news/ +cp -r ./blog/content/zh/post/* ../target/zh/post/ + +mkdir -p /usr/local/docs/target/en/events/ +mkdir -p /usr/local/docs/target/en/news/ +mkdir -p /usr/local/docs/target/en/post/ +cp -r ./website/content/en/events/* ../target/en/events/ +cp -r ./website/content/en/news/* ../target/en/news/ +cp -r ./blog/content/en/post/* ../target/en/post/ + + + +git clone https://gitee.com/opengauss/docs.git +cd ./docs + +for r in $(git branch -r --list "origin/*"); do + b=${r##*origin/} + # shellcheck disable=SC2170 + # shellcheck disable=SC1073 + # shellcheck disable=SC1072 + # shellcheck disable=SC1020 + # shellcheck disable=SC1009 + if [[ "master" != $b ]] && [[ "website" != $b ]] && [[ "HEAD" != $b ]] && [[ "->" != $b ]]; then + git checkout $b + mkdir -p /usr/local/docs/target/zh/docs/$b/docs + mkdir -p /usr/local/docs/target/en/docs/$b/docs + cp -r ./content/zh/docs/* /usr/local/docs/target/zh/docs/$b/docs/ + cp -r ./content/en/docs/* /usr/local/docs/target/en/docs/$b/docs/ + fi +done + + + diff --git a/EaseSearch/src/main/resources/script/opengauss/updateDoc.sh b/EaseSearch/src/main/resources/script/opengauss/updateDoc.sh new file mode 100644 index 0000000..e69de29 diff --git a/EaseSearch/src/test/java/com/search/docsearch/DocSearchApplicationTests.java b/EaseSearch/src/test/java/com/search/docsearch/DocSearchApplicationTests.java new file mode 100644 index 0000000..e48d92d --- /dev/null +++ b/EaseSearch/src/test/java/com/search/docsearch/DocSearchApplicationTests.java @@ -0,0 +1,79 @@ +package com.search.docsearch; + +import com.search.docsearch.config.MySystem; +import com.search.docsearch.constant.Constants; +import com.search.docsearch.utils.EulerParse; +import com.search.docsearch.utils.IdUtil; +import org.apache.commons.io.FileUtils; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +@SpringBootTest +class DocSearchApplicationTests { + @Autowired + @Qualifier("restHighLevelClient") + private RestHighLevelClient restHighLevelClient; + + @Autowired + @Qualifier("setConfig") + private MySystem s; + + + + @Test + void contextLoads() throws IOException { + + DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(""); + BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); + boolQueryBuilder.must(new TermQueryBuilder("lang", "zh")); + boolQueryBuilder.must(new TermQueryBuilder("type", "news")); + deleteByQueryRequest.setQuery(boolQueryBuilder); + BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT); + System.out.println(bulkByScrollResponse); + } + + + + @Test + void testPa() throws Exception { + File mdFile = FileUtils.getFile("C:\\CYDev\\workspace\\eulerdoc\\openEuler-portal\\app\\.vitepress\\dist\\zh\\learn\\mooc\\detail\\index.html"); + Map map = EulerParse.parse("zh", "download", mdFile); + + System.out.println(map); + + + IndexRequest indexRequest = new IndexRequest(s.index).id(IdUtil.getId()).source(map); + + IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); + System.out.println(indexResponse.toString()); +// String s = "012345"; +// System.out.println(s.substring(0, 6)); + } + + + + + + @Test + void ines() throws IOException { + String d = "2022-04-02"; + String archives = d.toString().substring(1, 13); + System.out.println(archives); + } + + +} -- Gitee