データベース(DB)のデータのインポートを開始して、すでに3時間が経過しようとしています。このインポートが、これまで作ってきたDBのテーブル全部を吹き飛ばすことがなかろうかと、とても心配しています。

江端智一のホームページ
データベース(DB)のデータのインポートを開始して、すでに3時間が経過しようとしています。このインポートが、これまで作ってきたDBのテーブル全部を吹き飛ばすことがなかろうかと、とても心配しています。
Q: 緯度、軽度の点からなる鉄道路線のCSVデータがあるのですが、これが線の順番に並んでおらず、バラバラの順番になっています。このcsvファイルを線の順番に並び替えるGo言語プログラムを作成して下さい。
点画にすれば、こんな感じ
でも、線画にすると、こんな感じになる
で、このcsvのファイル名を、"your_csv_file.csv"として、以下のプログラムに放り込む
package main
import (
"bufio"
"encoding/csv"
"fmt"
"io"
"math"
"os"
"strconv"
)
// 座標を表す構造体
type Coordinate struct {
Latitude float64
Longitude float64
}
func main() {
// CSVファイルのパス
filePath := "your_csv_file.csv"
// CSVファイルを読み込む
coordinates, err := readCoordinatesFromFile(filePath)
if err != nil {
fmt.Println("Error reading CSV file:", err)
return
}
// 座標を線の順番に並び替え
sortedCoordinates := sortCoordinates(coordinates)
// 結果を表示
for _, coord := range sortedCoordinates {
fmt.Printf("%f, %f\n", coord.Latitude, coord.Longitude)
}
}
// CSVファイルから座標を読み込む関数
func readCoordinatesFromFile(filePath string) ([]Coordinate, error) {
var coordinates []Coordinate
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
reader := csv.NewReader(bufio.NewReader(file))
for {
line, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
// CSVの各行から緯度と経度を抽出
latitude, err := strconv.ParseFloat(line[0], 64)
if err != nil {
return nil, err
}
longitude, err := strconv.ParseFloat(line[1], 64)
if err != nil {
return nil, err
}
coordinates = append(coordinates, Coordinate{Latitude: latitude, Longitude: longitude})
}
return coordinates, nil
}
// 座標を線の順番に並び替える関数
func sortCoordinates(coordinates []Coordinate) []Coordinate {
// 最初の座標をスタート地点として選択
startIndex := 0
sortedCoordinates := []Coordinate{coordinates[startIndex]}
coordinates = append(coordinates[:startIndex], coordinates[startIndex+1:]...)
// 座標を距離に基づいてソート
for len(coordinates) > 0 {
minIndex := findNearestCoordinateIndex(coordinates, sortedCoordinates[len(sortedCoordinates)-1])
sortedCoordinates = append(sortedCoordinates, coordinates[minIndex])
coordinates = append(coordinates[:minIndex], coordinates[minIndex+1:]...)
}
return sortedCoordinates
}
// 最も距離の近い座標のインデックスを検索する関数
func findNearestCoordinateIndex(coordinates []Coordinate, reference Coordinate) int {
minDistance := math.MaxFloat64
minIndex := 0
for i, coord := range coordinates {
distance := calculateDistance(coord, reference)
if distance < minDistance {
minDistance = distance
minIndex = i
}
}
return minIndex
}
// Haversine式を使用して座標間の距離を計算する関数
func calculateDistance(coord1, coord2 Coordinate) float64 {
earthRadius := 6371.0 // 地球の半径(キロメートル)
// 度数法からラジアンに変換
lat1 := degToRad(coord1.Latitude)
lon1 := degToRad(coord1.Longitude)
lat2 := degToRad(coord2.Latitude)
lon2 := degToRad(coord2.Longitude)
// Haversine式による距離計算
dlon := lon2 - lon1
dlat := lat2 - lat1
a := math.Pow(math.Sin(dlat/2), 2) + math.Cos(lat1)*math.Cos(lat2)*math.Pow(math.Sin(dlon/2), 2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
distance := earthRadius * c
return distance
}
// 度数法をラジアンに変換する関数
func degToRad(deg float64) float64 {
return deg * (math.Pi / 180)
}
でてきたcsvをファイルにして表示すると、こんな感じになった。
だいぶ良くなったんだけど、変な直線が一本引かれている。
考察した結果、このプログラムは、
(Step.1) 出発点に一番近いノードを探す。
(Step.2)そのノードを次の出発点にして(Step.1)を行う
という処理をしているため、使われていないノードが、候補として残ってしまうという問題が生じる。
で、終端に至ったノードは使われていないノードの中から、一番近いノードを探してくるため、このような問題が発生してしまう、ということだろう。
対策は結構簡単で、ノード距離が異様に大きい場合は、そこで打ち切る、という処理を入れれば足る
(面倒なので、今回は、手動で削除した)
以上
で「エクスポートをクリック」 → map.osmがダウンロードされる
JOSMで表示する
フィルタを選択
Ctrl-aで選択
「編集」→「座標をコピー」で、座標コピー
ここで、エディター等に(test.csvなどとして)コピーする。
を参照して、test.csvをQGISで表示する。
このように座標が取得できているのが確認できました。
根岸線を削除する場合、JOSMで場所を指定して丹念に削除していく
で、この座標さえ取れれば、
Go言語で、BusRouteの点で繋がれた線とみなして、trackingDataの各点から、その線からの最短距離を算出するようなプログラムの改造をお願いできますか?
が使えるようになる。
ダメ。これで取得した座標は、出現順番がバラバラになっているので、補正処理が必要となる。
今回の場合、南北方向にのみ伸びているので、緯度で並べかえれば良いが、そうでない場合は、別途処理が必要となると思うが(今回は必要ないので、これは省略)
この後であれば、上記のプログラムが使えるはず。
ちなみに、
osmosis --read-xml map.osm --tf accept-nodes railway=* --write-xml railway_nodes.osm
osmosis --read-xml map.osm --tf accept-relations railway=* --used-way --write-xml railway_data.osm
は、上手く動かせませんでした。
特別なネットワークツールを使わずに、ネットワークのトラフィックを計測する方法。
(WinDumpもWireSharkも面倒だなーと)
PowerShellから、これをコピペ(xxxx.batにする必要なし)すると、network_data.logというファイルができる
while ($true) {
$NetworkInterfaces = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' }
foreach ($NetworkInterface in $NetworkInterfaces) {
$Statistics = Get-NetAdapterStatistics -Name $NetworkInterface.Name
$ReceivedBytes = $Statistics.ReceivedBytes
$SentBytes = $Statistics.SentBytes
$TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$Record = "$TimeStamp, Interface: $($NetworkInterface.Name), Received Bytes: $ReceivedBytes bytes, Sent Bytes: $SentBytes bytes"
Add-Content -Path "network_data.log" -Value $Record
}
Start-Sleep -Seconds 10 # 10秒待機
}
で、network_data.logの内容は、以下の通り
PS C:\Users\azureuser> more .\network_data.log
2023-12-07 10:02:07, Interface: Ethernet 7, Received Bytes: 182088626 bytes, Sent Bytes: 1971150950 bytes
2023-12-07 10:02:07, Interface: Ethernet, Received Bytes: 183155088 bytes, Sent Bytes: 1882163584 bytes
2023-12-07 10:02:17, Interface: Ethernet 7, Received Bytes: 182107502 bytes, Sent Bytes: 1971187408 bytes
2023-12-07 10:02:17, Interface: Ethernet, Received Bytes: 183176035 bytes, Sent Bytes: 1882198919 bytes
2023-12-07 10:02:27, Interface: Ethernet 7, Received Bytes: 182141183 bytes, Sent Bytes: 1971266248 bytes
2023-12-07 10:02:27, Interface: Ethernet, Received Bytes: 183207355 bytes, Sent Bytes: 1882275443 bytes
で、ここで、"Ethernet 7"と、"Ethernet"の2つのインターフェースがあることが分かるので、
$NetworkInterfaces = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' -and $_.Name -eq 'Ethernet' }
とすると、'Ethernet' とか 'Ethernet 7'のどちらかを選ぶことができる。
ラズパイ4 + USBカメラ Webカメラ C270n HD 720P で、SRTストリームに変換してライブ映像を転送する方法(色々やってきたんだけど、この組み合わせだけがスポッと抜けていて、探すのに苦労した)
送信側
cam@cam-desktop:~$ gst-launch-1.0 v4l2src ! video/x-raw,format=YUY2,width=
受信側
cam@cam-desktop:~$ ffplay -i srt://localhost:8888
package main
import (
"fmt"
"github.com/paulmach/orb"
"github.com/paulmach/orb/planar"
)
// Point はデータ番号と緯度、経度を保持する構造体です
type Point struct {
Number int
Lat, Lon float64
}
// トラッキングデータとバス路線データの変換
func convertToOrbPoint(p Point) orb.Point {
return orb.Point{p.Lon, p.Lat}
}
func main() {
// トラッキングデータ
trackingData := []Point{
{1, 139.6268272, 35.3715607},
{2, 139.627135, 35.3719136},
{3, 139.6274291, 35.3721591},
{11, 139.6276967, 35.3724112},
{101, 139.6276253, 35.372575},
{59, 139.6274377, 35.3727348},
{7, 139.6272077, 35.3728485},
{99, 139.6263279, 35.3728985},
{111, 139.6262229, 35.3728182},
{131, 139.6260982, 35.3726421},
{200, 139.6260349, 35.3724965},
{32, 139.6257477, 35.3720127},
{42, 139.6254685, 35.3705626},
{44, 139.6254273, 35.3703156},
{46, 139.62361383758, 35.36644117332},
}
// バス路線データ
busRoute := []Point{
{0, 139.6272077, 35.3728485},
{0, 139.6263279, 35.3728985},
{0, 139.6262229, 35.3728182},
{0, 139.6260982, 35.3726421},
{0, 139.6260349, 35.3724965},
{0, 139.6257477, 35.3720127},
{0, 139.6254685, 35.3705626},
{0, 139.6254273, 35.3703156},
{0, 139.62361383758, 35.36644117332},
{0, 139.62386146588, 35.3665604971},
{0, 139.62412597981, 35.36668746811},
{0, 139.6245189, 35.3668106},
{0, 139.6250347, 35.367043},
{0, 139.62548981146, 35.36726113676},
}
// orbライブラリを使用して、トラッキングデータとバス路線データをorb.Pointのスライスに変換
var trackingPoints []orb.Point
var busRoutePoints []orb.Point
for _, p := range trackingData {
trackingPoints = append(trackingPoints, convertToOrbPoint(p))
}
for _, p := range busRoute {
busRoutePoints = append(busRoutePoints, convertToOrbPoint(p))
}
// トラッキングポイントからバス路線上の最も近い点までの距離を計算し、データ番号とともに出力
for _, trackPoint := range trackingData {
distance := planar.DistanceFrom(orb.LineString(busRoutePoints), convertToOrbPoint(trackPoint))
fmt.Printf("Tracking Point %d: Lat: %v, Lng: %v, Distance: %v meters\n", trackPoint.Number, trackPoint.Lat, trackPoint.Lon, distance)
}
}
出力結果
Tracking Point 1: Lat: 139.6268272, Lng: 35.3715607, Distance: 0.001145488357906135 meters
Tracking Point 2: Lat: 139.627135, Lng: 35.3719136, Distance: 0.0009375188544507943 meters
Tracking Point 3: Lat: 139.6274291, Lng: 35.3721591, Distance: 0.0007240789459736531 meters
Tracking Point 11: Lat: 139.6276967, Lng: 35.3724112, Distance: 0.0006560124160327593 meters
Tracking Point 101: Lat: 139.6276253, Lng: 35.372575, Distance: 0.0004991913560911751 meters
Tracking Point 59: Lat: 139.6274377, Lng: 35.3727348, Distance: 0.000256569074508911 meters
Tracking Point 7: Lat: 139.6272077, Lng: 35.3728485, Distance: 0 meters
Tracking Point 99: Lat: 139.6263279, Lng: 35.3728985, Distance: 0 meters
Tracking Point 111: Lat: 139.6262229, Lng: 35.3728182, Distance: 0 meters
Tracking Point 131: Lat: 139.6260982, Lng: 35.3726421, Distance: 0 meters
Tracking Point 200: Lat: 139.6260349, Lng: 35.3724965, Distance: 0 meters
Tracking Point 32: Lat: 139.6257477, Lng: 35.3720127, Distance: 0 meters
Tracking Point 42: Lat: 139.6254685, Lng: 35.3705626, Distance: 0 meters
Tracking Point 44: Lat: 139.6254273, Lng: 35.3703156, Distance: 0 meters
Tracking Point 46: Lat: 139.62361383758, Lng: 35.36644117332, Distance: 0 meters
SELECT * FROM records WHERE start_at = '2023-03-20 05:03:00'; start_atの時間順に表示するSQLを教えて下さい。
SELECT
*
FROM records ORDER
BY start_at ASC;
降順(新しいものから古いものへ)に並べ替えたい場合は、ASC
を DESC
に変更します:
SELECT
*
FROM records ORDER
BY start_at DESC;
select user_id, start_at, end_at from records order by start_at ASC where user_id = 7; のSQLは何が間違っていますか?
SELECT user_id, start_at, end_at FROM records WHERE user_id = 7 ORDER BY start_at ASC;
moove=# select place from records where id = 2; place ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"lat": 34.7325, "lng": 135.4986}, {"lat": 34.7326, "lng": 135.4989}, {"lat": 34.7326, "lng": 135.4989}, {"lat": 34.7327, "lng": 135.4995}, {"lat": 34.7327, "lng": 135.5}, {"lat": 34.7328, "lng": 135.5002}, {"lat": 34.733, "lng": 135.5006}, {"lat": 34.7331, "lng": 135.501}, {"lat": 34.7334, "lng": 135.5015}, {"lat": 34.7336, "lng": 135.5018}, {"lat": 34.7336, "lng": 135.5018}, {"lat": 34.7336, "lng": 135.5019}, {"lat": 34.7337, "lng": 135.5021}, {"lat": 34.734, "lng": 135.5024}, {"lat": 34.7343, "lng": 135.5026}, {"lat": 34.7346, "lng": 135.5024}, {"lat": 34.7347, "lng": 135.5024}, {"lat": 34.7346, "lng": 135.5024}, {"lat": 34.7345, "lng": 135.5025}, {"lat": 34.7343, "lng": 135.5027}, {"lat": 34.7343, "lng": 135.5029}, {"lat": 34.7342, "lng": 135.5031}, {"lat": 34.7344, "lng": 135.5035}, {"lat": 34.7344, "lng": 135.5035}, {"lat": 34.7344, "lng": 135.5035}] (1 row) で登場する、最初の{"lat": 34.7325, "lng": 135.4986}と、最後の {"lat": 34.7344, "lng": 135.5035}だけを取り出すSQL文を書いて下さい
WITH places AS (
SELECT jsonb_array_elements(place) AS place_elements
FROM records
WHERE id = 2
)
SELECT
(SELECT place_elements FROM places LIMIT 1) AS first_place,
(SELECT place_elements FROM places ORDER BY jsonb_array_length(place) DESC LIMIT 1) AS last_place
FROM records
WHERE id = 2;
select user_id from records; で出てくる異なるuser_id(整数)をピックアップするSQL文を教えて下さい
SELECT DISTINCT user_id FROM records;
指定された二つの位置情報間のデータを30秒ごとに補完するには、まず、始点と終点の位置情報と時刻を取得し、それらの間の差を求めます。次に、時間と位置の差を等間隔に分割して、各時点での位置を計算します。
以下のGoプログラムは、始点と終点の情報を基に30秒ごとの位置情報を補完する例です:
package main
import (
"fmt"
"time"
)
// Location は緯度と経度を保持する構造体です
type Location struct {
Lat, Lng float64
}
func main() {
// 初期位置情報
startLocation := Location{Lat: 34.665300, Lng: 135.224100}
endLocation := Location{Lat: 34.664900, Lng: 135.223900}
// 時刻の設定
startTime, _ := time.Parse("2006-01-02 15:04:05", "2023-03-03 07:39:30")
endTime, _ := time.Parse("2006-01-02 15:04:05", "2023-03-03 07:43:30")
// 各差を計算
duration := endTime.Sub(startTime)
latDiff := endLocation.Lat - startLocation.Lat
lngDiff := endLocation.Lng - startLocation.Lng
// 30秒ごとのデータを生成
interval := 30 * time.Second
for t := startTime; t.Before(endTime); t = t.Add(interval) {
fraction := t.Sub(startTime).Seconds() / duration.Seconds()
lat := startLocation.Lat + fraction*latDiff
lng := startLocation.Lng + fraction*lngDiff
fmt.Printf("Lat: %f, Lng: %f %v\n", lat, lng, t.Format("2006-01-02 15:04:05"))
}
}
このプログラムは、指定された時間間隔(この場合は30秒)で始点と終点の間の緯度と経度を計算し、その結果を出力します。始点と終点の間の時間差と距離差に基づき、等間隔に位置情報を補完しています。
Go言語で、指定された日時(文字列形式)に30秒ずつ加算して表示するプログラムを作成するには、まず日時を扱うための time
パッケージを利用します。以下は、その要件を満たす簡単な例です。
package main
import (
"fmt"
"time"
)
func main() {
// 初期の日時設定
startAt := "2023-03-01 03:38:00"
layout := "2006-01-02 15:04:05" // Goの時間フォーマット
// 文字列を time.Time 型に変換
t, err := time.Parse(layout, startAt)
if err != nil {
panic(err)
}
// 30秒ずつ加算して表示
for i := 0; i < 10; i++ { // 例として10回繰り返す
t = t.Add(30 * time.Second)
fmt.Println(t.Format(layout))
}
}
このプログラムでは、time.Parse 関数を使用して日時の文字列を time.Time 型に変換し、その後 time.Add メソッドを使って30秒ずつ加算しています。最後に、time.Format メソッドを使用して日時を指定された形式で表示しています。ここでは10回の繰り返しを行っていますが、必要に応じて繰り返し回数を変更できます。
これを、
とお願いしたのですが、上手く動かないようなので、Go言語で書いて貰いました。
/*
f:/しゅらばしゅう/有吉先生データ/Moove/2023-07/test1124.go
SELECT id, user_id, start_at, end_at, end_at - start_at, distance, prediction_type FROM records WHERE user_id = 43 ORDER BY start_at ASC; で選ばれた上記のSQLを、first_place, last_placeとして追記できるようにするには、どのように記述すれば良いですか。
で、作ってもらったプログラム
*/
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
_ "github.com/lib/pq"
)
type Record struct {
ID int
UserID int
StartAt string
EndAt string
Duration string
Distance float64
PredictionType int
FirstPlace Location
LastPlace Location
}
type Location struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
}
func main() {
// PostgreSQL データベースへの接続情報
const (
host = "192.168.0.23"
port = 15432
user = "postgres"
password = "password"
dbname = "moove"
)
// PostgreSQL データベースへの接続
connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
db, err := sql.Open("postgres", connStr)
if err != nil {
panic(err)
}
defer db.Close()
rows, err := db.Query("SELECT id, user_id, start_at, end_at, end_at - start_at, distance, prediction_type, place FROM records WHERE user_id = 43 ORDER BY start_at ASC")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var r Record
var placeJSON string
err := rows.Scan(&r.ID, &r.UserID, &r.StartAt, &r.EndAt, &r.Duration, &r.Distance, &r.PredictionType, &placeJSON)
if err != nil {
log.Fatal(err)
}
var places []Location
err = json.Unmarshal([]byte(placeJSON), &places)
if err != nil {
log.Fatal(err)
}
if len(places) > 0 {
r.FirstPlace = places[0]
r.LastPlace = places[len(places)-1]
}
fmt.Printf("%+v\n", r)
}
}
出力結果