草庐IT

记录es的基本使用

泛舟五湖之间 2024-03-26 原文
在上一篇的文章中,我们已经将es基本安装好了,并且kibana也已经安装好了,在本章中我们就利用kibana来使用es,
实践一下。主要的版本是
es7.9.3
kibana7.9.3
当然在使用es之前,我们需要新增一批数据进去,为了验证后面的用法而准备的数据。
本篇博客的思路基本就是按照es的基本概念来写的,用法上也是先从集群-->索引-->文档的基本的应用。
更复杂的应用我们会放到后续的博客中。

上一篇文章传送门

一、准备es示例数据

首先我们把示例数据下载下来,示例数据被我保存在了gitee中的helloes项目下:
https://gitee.com/xiezuozhen/hello-world/tree/master/HelloEs/src/test/resources/exampledata
可自行下载使用

我这里使用的是accounts.json,其中部分示例数据如下所示:

{"index":{"_id":"1"}}
{"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
{"index":{"_id":"6"}}
{"account_number":6,"balance":5686,"firstname":"Hattie","lastname":"Bond","age":36,"gender":"M","address":"671 Bristol Street","employer":"Netagy","email":"hattiebond@netagy.com","city":"Dante","state":"TN"}
{"index":{"_id":"13"}}
{"account_number":13,"balance":32838,"firstname":"Nanette","lastname":"Bates","age":28,"gender":"F","address":"789 Madison Street","employer":"Quility","email":"nanettebates@quility.com","city":"Nogal","state":"VA"}
{"index":{"_id":"18"}}
{"account_number":18,"balance":4180,"firstname":"Dale","lastname":"Adams","age":33,"gender":"M","address":"467 Hutchinson Court","employer":"Boink","email":"daleadams@boink.com","city":"Orick","state":"MD"}
{"index":{"_id":"20"}}
{"account_number":20,"balance":16418,"firstname":"Elinor","lastname":"Ratliff","age":36,"gender":"M","address":"282 Kings Place","employer":"Scentric","email":"elinorratliff@scentric.com","city":"Ribera","state":"WA"}
{"index":{"_id":"25"}}
{"account_number":25,"balance":40540,"firstname":"Virginia","lastname":"Ayala","age":39,"gender":"F","address":"171 Putnam Avenue","employer":"Filodyne","email":"virginiaayala@filodyne.com","city":"Nicholson","state":"PA"}
{"index":{"_id":"32"}}
{"account_number":32,"balance":48086,"firstname":"Dillard","lastname":"Mcpherson","age":34,"gender":"F","address":"702 Quentin Street","employer":"Quailcom","email":"dillardmcpherson@quailcom.com","city":"Veguita","state":"IN"}
{"index":{"_id":"37"}}
{"account_number":37,"balance":18612,"firstname":"Mcgee","lastname":"Mooney","age":39,"gender":"M","address":"826 Fillmore Place","employer":"Reversus","email":"mcgeemooney@reversus.com","city":"Tooleville","state":"OK"}
{"index":{"_id":"44"}}
{"account_number":44,"balance":34487,"firstname":"Aurelia","lastname":"Harding","age":37,"gender":"M","address":"502 Baycliff Terrace","employer":"Orbalix","email":"aureliaharding@orbalix.com","city":"Yardville","state":"DE"}
{"index":{"_id":"49"}}
{"account_number":49,"balance":29104,"firstname":"Fulton","lastname":"Holt","age":23,"gender":"F","address":"451 Humboldt Street","employer":"Anocha","email":"fultonholt@anocha.com","city":"Sunriver","state":"RI"}
{"index":{"_id":"51"}}
{"account_number":51,"balance":14097,"firstname":"Burton","lastname":"Meyers","age":31,"gender":"F","address":"334 River Street","employer":"Bezal","email":"burtonmeyers@bezal.com","city":"Jacksonburg","state":"MO"}
{"index":{"_id":"56"}}
{"account_number":56,"balance":14992,"firstname":"Josie","lastname":"Nelson","age":32,"gender":"M","address":"857 Tabor Court","employer":"Emtrac","email":"josienelson@emtrac.com","city":"Sunnyside","state":"UT"}

当我们拿到示例数据后,我们可以通过进入宿主进行导入,

curl -H 'Content-Type:application/x-ndjson' -XPOST '192.168.47.210:9200/bank/account/_bulk?pretty' --data-binary "@accounts.json"

这里需要将accounts.json最后留一个空行,才能成功。
也可以利用kibana的可视化工具导入,不过可视化导入我这里导入的数据有点问题,所以这里就不展示kibana可视化导入了。
现在数据准备完毕,我们可以开始应用了。

二、查看es集群的相关信息的方法

主要分为了两类,一类为_cat,一类为_cluster

一、_cat的用法

我这里仅仅是列举了部分常用的用法,如果想要查看关于cat的其他的用法可以参考官方文档
https://www.elastic.co/guide/en/elasticsearch/reference/current/cat.html
GET /_cat/nodes?v&pretty #查看所有节点信息
GET /_cat/shards?v&pretty #查看各shard的详细情况
GET /_cat/master?v&pretty #查看master节点信息
GET /_cat/indices?v&pretty #查看集群中所有index的详细信息
GET /_cat/segments?v&pretty  #查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘
GET /_cat/count?v&pretty  #查看当前集群的doc数量
GET /_cat/recovery?v&pretty #查看集群内每个shard的recovery过程.调整replica。
GET /_cat/health?v&pretty #查看集群当前状态:红、黄、绿
GET /_cat/pending_tasks?v&pretty #查看当前集群的pending task,即挂起的任务
GET /_cat/aliases?v&pretty #查看集群中所有alias信息,路由配置等
GET /_cat/thread_pool?v&pretty #查看集群各节点内部不同类型的threadpool的统计信息,
GET /_cat/plugins?v&pretty #查看集群各个节点上的plugin信息
GET /_cat/fielddata?v&pretty #查看当前集群各个节点的fielddata内存使用情况
GET /_cat/nodeattrs?v&pretty #查看单节点的自定义属性
GET /_cat/repositories?v&pretty #输出集群中注册快照存储库
GET /_cat/templates?v&pretty #输出当前正在存在的模板信息

我选择几个在生产环境中用的比较多的进行讲解:

一、节点信息查询

GET /_cat/nodes:查看所有的节点信息

ip             heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.47.210           64          91   2    0.05    0.10     0.13 dilmrt    *      es3
192.168.47.210           58          91   2    0.05    0.10     0.13 dilmrt    -      es1
192.168.47.210           70          91   2    0.05    0.10     0.13 dilmrt    -      es2

heap.percent 堆内存占用百分比
ram.percent 内存占用百分比
cpu CPU占用百分比
master *表示节点是集群中的主节点
name 节点名

二、别名信息查询

GET /_cat/aliases?v&pretty 查询所有的别名信息

alias                   index                          filter routing.index routing.search is_write_index
.kibana-event-log-7.9.3 .kibana-event-log-7.9.3-000001 -      -             -              true
ilm-history-2           ilm-history-2-000001           -      -             -              true
.kibana                 .kibana_1                      -      -             -              -
.security               .security-7                    -      -             -              -
.kibana_task_manager    .kibana_task_manager_1         -      -             -              -

alias 索引的别名
index 索引名
routing.index 索引路由
routing.search 搜索路由
filter 过滤

别名是es中非常重要的一个功能。不仅生产中经常用到,而且面试里面也经常会提起

三、索引信息查询

GET /_cat/indices?v&pretty

health status index                          uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .security-7                    eY2dGhuKRpKcrnW_1dcAHg   1   1          7            0       51kb         25.5kb
green  open   .kibana-event-log-7.9.3-000001 FR7mcABbTZOWS_rLSnmHPQ   1   1          2            0     21.8kb         10.9kb
green  open   .apm-custom-link               Xwzboc0UTWaAxXIRBFm0jw   1   1          0            0       416b           208b
green  open   .kibana_task_manager_1         6rW9n3yJRuSqZGR44QjlGw   1   1          6         3741        1mb          588kb
green  open   .apm-agent-configuration       aNXRDK5FR0q-ZNbwVx54XA   1   1          0            0       416b           208b
green  open   .async-search                  1Q_H4j1URoucJXkurKelZA   1   1          0            1      6.6kb          3.3kb
green  open   .kibana_1                      EjDRMq5iSEOK6QitQqO4QQ   1   1         74           14     20.9mb         10.4mb
green  open   account                        LbMvFKxOR3mjfT9rflN7JA   1   1       1999            0      743kb        371.5kb

health 索引的健康状态
index 索引名
pri 索引主分片数量
rep 索引复制分片 数
store.size 索引主分片 复制分片 总占用存储空间
pri.store.size 索引总占用空间, 不计算复制分片 占用空间

还有其他的用法就不一一列举了,如果想查询更详细的信息自己可以翻阅官方文档

二、_cluster的用法

其实_cluster和_cat的用法差不多,返回的信息要比_cat详细的多,_cat一般是查看集群的相关信息,_cluster不仅可以查看,而且还可以对集群进行操作。
主要的命令有:

GET _cluster/health 	#查看集群健康状态接口
GET _cluster/state	#查看集群状况接口
GET _cluster/stats	#查看集群统计信息接口
GET _cluster/pending_tasks	#查看集群挂起的任务接口
POST _cluster/reroute	#集群重新路由操作(这个操作一般是在分片失败时使用,可以使用此命令重新尝试分片)
PUT _cluster/settings	#更新集群设置
GET _nodes/stats	#节点状态
GET _nodes	#节点信息
GET _nodes/hot_threads	#节点的热线程
GET nodes/_master/_shutdown	#关闭节点

这里详细列举其中几个即可:

一、集群健康信息

GET _cluster/health

{
  "cluster_name" : "elasticsearch-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 9,
  "active_shards" : 18,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

status:es集群状态

green:所有的主分片和副本父分片都已分配,集群100%可用。
yellow:所有的主分片已经分片,但至少还有一个副本分片是缺失的。不会有数据丢失,所以搜索结果依然是完整的。
不过高可用性在某种程度上被弱化。如果更多的分片消失,就会丢数据。
red:至少一个主分片(以及它的全部副本)都在丢失中。搜索只能返回部分数据,而分配到这个分片的写入请求会返回一个异常。

timed_out:是否超时
number_of_nodes :节点数
number_of_data_nodes:数据节点数
active_primary_shards:集群中所有索引的主分配数
active_shards:集群中所有索引的分片数
relocating_shards:当前正在节点间迁移的分片,该值在正常情况下为0,但在ES集群有节点加入或移除时,集群会发现分片分布不均衡,便会开始进行分片迁移。
initializing_shards:初始化中的分片数。往往在分片刚被创建或节点重启时,会经历短暂的initializing状态。
unassigned_shards:未分配的分片数。表示集群中存在分片但实际又找不到分片,常见于存在未分配的副本,如集群中有1个节点,有一个索引有5个分片1个副本,由于ES的灾备原则,副本分片不能与主分配保存在同一个节点中,那么就会有5个副本分片处于未分配状态。

二、集群状态信息

GET _cluster/state

{
  "cluster_name" : "elasticsearch-cluster",
  "cluster_uuid" : "uY2HW2E1S4m_Y2N5YSBeJQ",
  "version" : 492,
  "state_uuid" : "sksdPfrxSDKBZTMWJBTTRg",
  "master_node" : "jW8PbSdhTOOpESX13DRBJQ",
  "blocks" : { },
  "nodes" : {***},
  "metadata" : {***},
  "routing_table" : {***},
  "routing_nodes" : {}
}

由于数据量比较大,所以我这里仅仅是把其中重要的几部分罗列出来了
nodes:节点
metadata:主要是元数据信息,包括集群元信息和索引元信息
routing_table:路由表
routing_nodes:路由节点

三、关于index的一些用法

前面的基本都是对集群的查询,接下来我们学习一下关于索引的增删改查。

一、索引删除功能

DELETE bank 表示删除bank索引
当然还可以批量删除
DELETE bank*就是将以bank开头的索引全部删除

二、索引新增功能

如代码所示,我们新增一个banks索引。

PUT /banks/
{
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "account_number" : {
          "type" : "long"
        },
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "balance" : {
          "type" : "long"
        },
        "city" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "email" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "employer" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "firstname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "gender" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "lastname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "state" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "number_of_shards" : "1",
        "number_of_replicas" : "1"
      }
    }
  }

三、索引修改功能

由于在搜索引擎中,单纯对索引的修改,一般是先删除原来的索引,然后重建索引。

四、索引查询功能

GET bank
查询索引的相关信息
返回结果:

{
  "bank" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "account_number" : {
          "type" : "long"
        },
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "balance" : {
          "type" : "long"
        },
        "city" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "email" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "employer" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "firstname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "gender" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "lastname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "state" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1679827093469",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "FbFyX5TdRGC88ZlbvnemmQ",
        "version" : {
          "created" : "7090399"
        },
        "provided_name" : "bank"
      }
    }
  }
}

四、关于文档的一些用法

根据id查询索引下的某一个文档

GET bank/_doc/1
返回结果:

{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "account_number" : 1,
    "balance" : 39225,
    "firstname" : "Amber",
    "lastname" : "Duke",
    "age" : 32,
    "gender" : "M",
    "address" : "880 Holmes Lane",
    "employer" : "Pyrami",
    "email" : "amberduke@pyrami.com",
    "city" : "Brogan",
    "state" : "IL"
  }
}

根据id删除某一个文档

DELETE bank/_doc/1
返回结果:

{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1000,
  "_primary_term" : 1
}

根据id(自定义id)新增

 PUT bank/_doc/1
 {
"account_number" : 1,
"balance" : 39225,
"firstname" : "Amber",
"lastname" : "Duke",
"age" : 32,
"gender" : "M",
"address" : "880 Holmes Lane",
"employer" : "Pyrami",
"email" : "amberduke@pyrami.com",
"city" : "Brogan",
"state" : "IL"  
}

返回结果:

{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1001,
  "_primary_term" : 1
}

根据id进行修改文档

PUT bank/_doc/1
{
"account_number" : 1,
"balance" : 39225,
"firstname" : "Amber_xzz",
"lastname" : "Duke",
"age" : 32,
"gender" : "M",
"address" : "880 Holmes Lane",
"employer" : "Pyrami",
"email" : "amberduke@pyrami.com",
"city" : "Brogan",
"state" : "IL"
}

我们将firstname=Amber修改为firstname=Amber_xzz,然后提交
返回结果为:

{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1002,
  "_primary_term" : 1
}

其实kibana还有一个比较好用的地方,就是如下图所示的:

当我们对于某些查询的用法不是很了解时,我们可以通过图中所示的功能,直接定位到对应的详细文档,相当便捷。后续的很多的查询功能我不清楚时,也是通过这个文档来查看的。
我们这里仅仅是一些简单的使用,后续博客还会有很多关于查询的功能的使用。敬请期待…

有关记录es的基本使用的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐