Este artículo no involucra los principios específicos de ElasticSearch, sino solo registra cómo importar rápidamente datos en MySQL para la búsqueda de texto completo.
En el trabajo, debe implementar una función de búsqueda e importar datos de base de datos existentes. El líder del equipo recomienda usar ElasticSearch para implementarlo. Puede buscar tutoriales en línea, que son artículos relativamente antiguos. No tengo más remedio que explorarlo yo mismo. Consulte la documentación de ES y finalmente cree el servicio. Lo grabaré. Espero que los amigos con las mismas necesidades puedan evitar los desvíos y puedan construir rápidamente un servicio de Elasticsearch disponible de acuerdo con este tutorial.
ES Construcción
ES Builds puede descargar directamente archivos zip y contenedores Docker. Relativamente hablando, Docker es más adecuado para nosotros ejecutar servicios ES. Es posible construir fácilmente un clúster o crear un entorno de prueba. El método del contenedor también se usa aquí. Primero, necesitamos un Dockerfile:
Desde docker.elastic.co/elasticsearch/elasticsearch-oss:6.0.0# La configuración Enviar incluye el nuevo Elasticsearch.yml y los archivos de KeyStore.jks Copy-Chown = Elasticsearch: Elasticsearch conf//usr/share/elasticsearch/config/# install ikrun ./elasticsearch-pplugin instalación a la plataforma https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.0.0/elasticsearch-analysis-ik-6.0.0.zip# Instale ReadonlyRestrun ./bin/elastic-plugin Install https://github.com/hyy-yu/beziercurvedemo/raw/master/readonlyrest-1.16.14_es6.0.0.zipuser elasticsearchcmd ./bin/elasticsearch
Aquí hay una explicación de la operación anterior:
Configuración de Eltication Elasticsearch.yml
cluster.name: "docker-cluster"network.host: 0.0.0.0# minimum_master_nodes need to be explicitly set when bound on a public IP# set to 1 to allow single node clusters# Details: https://github.com/elastic/elasticsearch/pull/17288discovery.zen.minimum_master_nodes: 1# Forbid the system to exchange memory on Es bootstrap.memory_lock: true http.type: ssl_netty4readonlyrest: habilitar: true ssl: habilitar: true keystore_file: "server.jks" keystore_pass: servidor key_pass: servidor access_control_rules: - nombre: "bloque 1 - root" tyte: "Permitir grupos: [" administrador "] - nombre:" Usuario "GRUPOS" - GRUPOS "GRUSOS") ["Paper*"] Acciones: ["Indices: Data/Read/*"] Usuarios: - Nombre de usuario: root Auth_key_SHA256: CB7C98bae153065db931980a13bd45ee3a77cb8f27a7dfee68f686377acc33f1 Grupos: ["administrador"] - ") Xiaoming: grupos de Xiaoming: ["Usuario"]
Aquí Bootstrap.Memory_Lock: True es un pozo, que prohíbe el intercambio de memoria. El documento ya ha explicado que algún sistema operativo intercambiará memoria temporalmente no utilizada a un área del disco duro durante el tiempo de ejecución. Sin embargo, este comportamiento se elevará la tasa de utilización de recursos de ES e incluso hará que el sistema no pueda responder.
Ya es obvio en el archivo de configuración que un usuario raíz pertenece al grupo de administración, y el administrador tiene todos los permisos. Debido a que Xiaoming está en el grupo de usuarios, solo puede acceder al índice de papel y solo puede leer, pero no puede operar. Para una configuración más detallada, consulte: Documentación de ReadonlyRest
En este punto, se han completado los preparativos para ES. Docker Build -t Esimage: Etiqueta. Docker Run -P 9200: 9200 Esimage: Etiqueta Run.
Si https://127.0.0.1:9200/ regresa
{"Nombre": "VAKWRIR", "Cluster_Name": "Docker-Cluster", "Cluster_Uuid": "YSyDowkvrH2SWZ907S2M_W", "Versión": {"Número": "6.0.0", "Build_hash": "8F0685B", "Build_Date"::: ": "2017-11-10t18: 41: 22.859z", "build_snapshot": false, "lucene_version": "7.0.1", "minter_wire_compatibility_version": "5.6.0", "minter_index_compatibility_version": "5.0.0"}, "tagline": "sabes, para la búsqueda" para la búsqueda "}Ha aparecido el protagonista de nuestro tutorial. Compartiré varias API de uso común para provocar y depurar ES:
{{URL}} se reemplaza con su dirección ES local.
Importar datos MySQL
Estoy usando datos mySQL aquí, pero de hecho, otras bases de datos son las mismas. La clave es cómo importar. El tutorial en línea recomendará el complemento MySQL para Logstash, Beat y ES para la importación. También lo he probado. La configuración es engorrosa y los documentos son escasos. Si la estructura de la base de datos es un poco complicada, la importación es una tarea laboriosa, por lo que no se recomienda. De hecho, ES tiene bibliotecas API correspondientes en cada idioma. Puede ensamblar los datos en JSON a nivel de idioma y enviarlos a ES a través de la biblioteca API. El proceso es más o menos como sigue:
Yo uso la biblioteca ES de Golang elastic. Puede buscar en GitHub otros idiomas, y el método de operación es el mismo.
A continuación, use una base de datos simple para presentarla:
Mesa de papel
| identificación | nombre |
|---|---|
| 1 | Beijing No. 1 Simulación de la escuela primaria |
| 2 | Jiangxi Beijing Preguntas de examen de ingreso a la universidad |
Mesa de la provincia
| identificación | nombre |
|---|---|
| 1 | Beijing |
| 2 | Jiangxi |
Paper_province mesa
| Paper_id | provincia_id |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
Como se mencionó anteriormente, el papel y la provincia son relaciones de muchas a muchos. Ahora que los datos en papel se ingresan en ES, puede buscar difuso por el nombre del papel o filtrar a través de la provincia. El formato de datos JSON es el siguiente:
{"id": 1, "Nombre": "Volumen de simulación de la escuela primaria Beijing No. 1", "Provincias": [{"id": 1, "Nombre": "Beijing"}]} Primero prepare un archivo MAPPPING.JSON, que es la definición de la estructura de almacenamiento de datos en ES.
{"Mapeaciones": {"Docs": {"include_in_all": false, "Propiedades": {"id": {"tipo": "long"}, "nombre": {"tipo": "text", "analzer": "ik_max_word" // usa el parterador de palabras más grande}, "provinces": {"tipo": "nested": "n. "id": {"type": "entero"}, "nombre": {"tipo": "text", "índice": "falso" // no indexado}}}}}}}}}}}}, "configuración": {"number_of_shards": 1, "number_of_riquasCabe señalar que el campo _All se cancela. Este valor predeterminado recopilará todos los campos de almacenamiento para lograr una búsqueda restringida incondicional. La desventaja es que el espacio ocupa mucho.
Establecí el número de fragmentos en 1, y no se establecen réplicas. Después de todo, este no es un clúster y los datos procesados no son mucho. Si hay una gran cantidad de datos que deben procesarse, puede establecer la cantidad de fragmentos y réplicas usted mismo.
Primero, establecer una conexión con ES, CA.CRT está relacionada con la auto-firma de JKS. Por supuesto, aquí estoy usando InseguresKipverify para ignorar la verificación del archivo de certificado.
Func InitelasticSearch () {Pool: = x509.newCertPool () crt, err0: = ioutil.readfile ("conf/ca.crt") if err0! = nil {no veaPenes (err0, "read CRT archivo err") return} pisceendcertsfrompem (CRT) tr: = & http.transport {tlscLeTconfig. & tls.config {rootCas: Pool, Insegureskipverify: true},} httpClient: = & http.client {transport: tr} // background Construct Elastic Var error elasticClient, err = elastic.newclient (elastic.seturl (myconfig.elasticurl), elastic.setSorLoG (getLoG (getLoG (getLoGer (getLoGer () elastic.setgzip (true), elastic.sethttpClient (httpclient), elastic.setsniff (false), // clúster sniff, recuerde cerrar un solo nodo. "Search_client_error") return} // ElasticClient Construction se completa // consulta si existe un índice de papel, err: = elasticClient.IndexExists (myconfig.elasticindexname) .do (context.background ()) si err! = nil {no vDingOpenes (err, ", "_index_check) regresa} // the Índice exist y pase el índice y pase el índice y pase los datos, no los datos, los datos, no sean los datos, los datos, el índice y los datos, el índice y los datos, los datos, el índice y los datos, el índice y los datos existentes, no sean. Si existe {if! isIndexInteGricity (elasticClient) {// Elimine el índice actual y prepárese para reconstruir la respuesta, err: = elasticClient.deleteIndex (myconfig.elasticindexname) .do (context.background ()) if err! = nil || ! Deleteresponse.acknowledged {CankOpenes (err, "delete_index_error") return}} else {return}} // base de datos de consultas de fondo y envía datos a elasticsearch go fetchdbgetallpaperandsendToes ()} type Papersearch struct {PaperId int64 `gorm:" primario_key; columna: f_paper_id; type: bigInt (20) "json:" id "` string de nombre `gorm:" columna: f_name; size: 80 "json:" nombre "` provincias [] provincia `gorm:" muchos2many: t_paper_province; " JSON: "Provincias" `// provincias para las cuales el documento de prueba es aplicable} func fetchdbgetallpaperandsendToes () {// fetch Paper var Allpaper [] Papersearch getDb (). Table (" T_Papers "). Find (& AllPaper) // Province para i: = Range Allpaper {Var AllPro [] provincia GetDb (). Table ("T_Provinces"). June ("Inner Join` t_paper_province` en `t_paper_province`.`province_f_province_id` =` t_provinces`.`f_province_id`) .Where ("t_province.paper_f_paper_id =?", ",", Allpaper [i] .paperId) .Find (& AllPro) Allpaper [i] .Provinces = allPro} if len (Allpaper)> 0 {// Enviar a ES - Crear índice CreateService: = getELasticeSearch (). CreateIndex (myconfig.elasticindexNexName) // El índice_default_setting aquí está el contenido in Mappping.json anterior. createService.body (index_default_setting) crereatersult, err: = createService.do (context.background ()) if err! = nil {no vidaOpenes (err, "create_paper_index") return} if! CreateResult.ackNowged || - Enviar todo el papel bulkrequest: = getElasticsearch (). Bulk () para i: = range Allpaper {indexReq: = elastic.newbulkindexRequest (). optype ("create"). index (myConfig.elasticindexname) .Type ("docs"). Doc (Allpaper [i]) bulkRequest.add (indexReq)} // do envía las solicitudes a granel a ElasticSearch bulkResponse, err: = bulkRequest.do (context.background ()) Si err! = Nil {no puedo ! = Len (Allpaper) {CankOpenes (err, "insert_docs_nums_error") return} // Enviar éxito}} Después de ejecutar el código anterior, use {{URL}}/_ Inídes Cat/V para ver si el índice recién creado aparece en ES y use {{URL}}/documentos/_Search para ver cuántos documentos alcanzan. Si el número de documentos es igual a la cantidad de datos que envió en el pasado, el servicio de búsqueda se considerará en ejecución.
buscar
Ahora puede buscar documentos de prueba por ProvinceID y Q, y el valor predeterminado se clasifica por puntaje de relevancia.
// Q Search String String ProvinceID Limited Province Id Limit Pagination Parametros Func SearchPaper (Q String, ProvinceID Uint, Limit int, Page int) (List [] Papersearch, TotalPage int, CurrentPage int, PageSend int, returnerr Error) {// Si las condiciones no se cumplen, use la base de datos para buscar si! CanuseSelasticsearch &&! MyConfig.uselasTicSear courseId, gradeId, provinceId, paperTypeId, limit, page) } list = make([]PaperSimple, 0) totalPage = 0 currentPage = page pageIsEnd = 0 returnErr = nil client := GetElasticSearch() if client == nil { return SearchPaperLocal(q, courseId, gradeId, provinceId, paperTypeId, limit, page) } // There is a problem with ElasticSearch, use the Base de datos para buscar si! IsIndexInteGricity (Client) {return SearchPaperLocal (Q, CourseID, GradeId, ProvinceID, PapertypeId, Limit, Page)} if! Client.isrunning () {Client.start ()} Derfer Client.stop () q = html.ScapeString (q) boolquery: = elastic.newboolQuery () / // //// / / /.Acmery elastic.newMatchQuery ("nombre", q) // provincia si ProvinceID> 0 && ProvinceID! = default_province_all {probol: = elastic.newboolquery () tpro: = elastic.newtermQuery ("provinces.id", provinceid) pronesto: = elastic.newnedequery ("provinces", probinkes (probin.must (province) boolQuery.must (pronEST)} boolQuery.must (matchQuery) para _, e: = range termQualerys {boolquery.must (e)} stoppectt: = elastic.newhighlight () stopalt.field (elastic_search_search_field_name) stopal.Prushags (elastic_search_field_tag_start) stop stop.posttags (elastic_search_search_field_tag_end) searchResult, err2: = client.search (myconfig.elasticindexname). Lo más destacado (Highligt). Consulta (boolquery). Desde ((Página - 1) * Límite). Tamaño (límite). Do (context.background ()) if Err2! = Nil {// Handle Error getLogger (). LogErR ("Error ocurrió al buscar"+err2.Error (), "search_error") // Error de manejo returnerR = errores.new ("Error ocurrió durante la búsqueda")} más {Si searchResult.hits.totalhits> 0 {// iterate a través de los resultados para los resultados para los resultados de los resultados para {Range {si se apunte a los resultados. searchResult.Hits.Hits { var p PaperSearch err := json.Unmarshal(*hit.Source, &p) if err != nil { // Deserialization failed GetLogger().LogErr("Error occurred during search"+err.Error(), "search_deserialization_error") returnErr = errors.New("Error during searching") return } if Len (hit.highlight [elastic_search_search_field_field_name])> 0 {p.name = hit.highlight [elastic_search_search_field_field_name] [0]} list = append (list, p)} Count: = SearchResult.totalhits () CurrentPage = Page If if Count> 0 {TotalPage = int (Math.Ceil (float64 (Count) float64 (límite)))} if currentPage> = totalPage {pageIsend = 1}} else {// no golpes}} return}Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.